From 2ff40618e50cb8b790f6efa96c9b6e169dfc4cdc Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:33:33 -0500 Subject: [PATCH 01/34] made test work --- .../data/annotation_types/__init__.py | 1 - .../data/annotation_types/base_annotation.py | 4 +- .../classification/__init__.py | 2 +- .../classification/classification.py | 69 ++++++---------- .../labelbox/data/annotation_types/feature.py | 27 +++---- .../labelbox/data/annotation_types/label.py | 3 +- .../llm_prompt_response/prompt.py | 8 +- .../data/annotation_types/metrics/base.py | 3 +- .../metrics/confusion_matrix.py | 9 ++- .../data/annotation_types/metrics/scalar.py | 3 +- .../annotation_types/ner/document_entity.py | 7 +- .../data/annotation_types/ner/text_entity.py | 6 +- .../data/annotation_types/relationship.py | 4 +- .../labelbox/data/annotation_types/video.py | 9 ++- libs/labelbox/src/labelbox/data/mixins.py | 35 ++++---- libs/labelbox/src/labelbox/data/ontology.py | 9 +-- .../data/serialization/ndjson/base.py | 7 +- .../serialization/ndjson/classification.py | 13 +-- .../data/serialization/ndjson/label.py | 7 +- .../data/serialization/ndjson/metric.py | 2 +- .../data/serialization/ndjson/objects.py | 13 +-- .../src/labelbox/pydantic_serializers.py | 21 +++++ .../src/labelbox/schema/data_row_metadata.py | 11 +-- .../src/labelbox/schema/export_task.py | 7 +- .../src/labelbox/schema/foundry/app.py | 8 +- libs/labelbox/src/labelbox/schema/ontology.py | 3 +- libs/labelbox/src/labelbox/utils.py | 3 +- .../classification/test_classification.py | 80 +++++-------------- 28 files changed, 170 insertions(+), 204 deletions(-) create mode 100644 libs/labelbox/src/labelbox/pydantic_serializers.py diff --git a/libs/labelbox/src/labelbox/data/annotation_types/__init__.py b/libs/labelbox/src/labelbox/data/annotation_types/__init__.py index 85b7ae1af..4de812bf4 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/__init__.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/__init__.py @@ -29,7 +29,6 @@ from .classification import Checklist from .classification import ClassificationAnswer -from .classification import Dropdown from .classification import Radio from .classification import Text diff --git a/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py b/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py index 4a16b8b17..b7c510083 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py @@ -1,15 +1,15 @@ import abc from uuid import UUID, uuid4 from typing import Any, Dict, Optional -from labelbox import pydantic_compat from .feature import FeatureSchema +from pydantic import PrivateAttr class BaseAnnotation(FeatureSchema, abc.ABC): """ Base annotation class. Shouldn't be directly instantiated """ - _uuid: Optional[UUID] = pydantic_compat.PrivateAttr() + _uuid: Optional[UUID] = PrivateAttr() extra: Dict[str, Any] = {} def __init__(self, **data): diff --git a/libs/labelbox/src/labelbox/data/annotation_types/classification/__init__.py b/libs/labelbox/src/labelbox/data/annotation_types/classification/__init__.py index c396a510f..5bb098730 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/classification/__init__.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/classification/__init__.py @@ -1,2 +1,2 @@ -from .classification import (Checklist, ClassificationAnswer, Dropdown, Radio, +from .classification import (Checklist, ClassificationAnswer, Radio, Text) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py index 9a1867ff2..b0bca72ae 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py @@ -1,5 +1,4 @@ from typing import Any, Dict, List, Union, Optional -import warnings from labelbox.data.annotation_types.base_annotation import BaseAnnotation from labelbox.data.mixins import ConfidenceMixin, CustomMetricsMixin @@ -9,18 +8,9 @@ except: from typing_extensions import Literal -from labelbox import pydantic_compat +from pydantic import BaseModel, model_serializer from ..feature import FeatureSchema - - -# TODO: Replace when pydantic adds support for unions that don't coerce types -class _TempName(ConfidenceMixin, pydantic_compat.BaseModel): - name: str - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) - res.pop('name') - return res +from labelbox.pydantic_serializers import feature_serializer class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): @@ -38,59 +28,47 @@ class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): keyframe: Optional[bool] = None classifications: List['ClassificationAnnotation'] = [] - def dict(self, *args, **kwargs) -> Dict[str, str]: - res = super().dict(*args, **kwargs) - if res['keyframe'] is None: - res.pop('keyframe') - if res['classifications'] == []: - res.pop('classifications') - return res + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return feature_serializer(handler(self)) - -class Radio(ConfidenceMixin, CustomMetricsMixin, pydantic_compat.BaseModel): +class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ A classification with only one selected option allowed >>> Radio(answer = ClassificationAnswer(name = "dog")) """ answer: ClassificationAnswer + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return feature_serializer(handler(self)) -class Checklist(_TempName): +class Checklist(ConfidenceMixin, BaseModel): """ A classification with many selected options allowed >>> Checklist(answer = [ClassificationAnswer(name = "cloudy")]) """ - name: Literal["checklist"] = "checklist" answer: List[ClassificationAnswer] + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return feature_serializer(handler(self)) -class Text(ConfidenceMixin, CustomMetricsMixin, pydantic_compat.BaseModel): +class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ Free form text >>> Text(answer = "some text answer") """ answer: str - - -class Dropdown(_TempName): - """ - - A classification with many selected options allowed . - - This is not currently compatible with MAL. - - Deprecation Notice: Dropdown classification is deprecated and will be - removed in a future release. Dropdown will also - no longer be able to be created in the Editor on 3/31/2022. - """ - name: Literal["dropdown"] = "dropdown" - answer: List[ClassificationAnswer] - - def __init__(self, **data: Any): - super().__init__(**data) - warnings.warn("Dropdown classification is deprecated and will be " - "removed in a future release") + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return feature_serializer(handler(self)) class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, @@ -110,8 +88,9 @@ class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, extra (Dict[str, Any]) """ - value: Union[Text, Checklist, Radio, Dropdown] + value: Union[Text, Checklist, Radio] message_id: Optional[str] = None - -ClassificationAnswer.update_forward_refs() + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return feature_serializer(handler(self)) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/feature.py b/libs/labelbox/src/labelbox/data/annotation_types/feature.py index 21e3eb413..aa9063cf4 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/feature.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/feature.py @@ -1,11 +1,10 @@ from typing import Optional - -from labelbox import pydantic_compat - +from pydantic import BaseModel, model_validator, model_serializer from .types import Cuid +from labelbox.pydantic_serializers import feature_serializer -class FeatureSchema(pydantic_compat.BaseModel): +class FeatureSchema(BaseModel): """ Class that represents a feature schema. Could be a annotation, a subclass, or an option. @@ -14,18 +13,14 @@ class FeatureSchema(pydantic_compat.BaseModel): name: Optional[str] = None feature_schema_id: Optional[Cuid] = None - @pydantic_compat.root_validator - def must_set_one(cls, values): - if values['feature_schema_id'] is None and values['name'] is None: + @model_validator(mode="after") + def must_set_one(self): + if self.feature_schema_id is None and self.name is None: raise ValueError( "Must set either feature_schema_id or name for all feature schemas" ) - return values - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) - if 'name' in res and res['name'] is None: - res.pop('name') - if 'featureSchemaId' in res and res['featureSchemaId'] is None: - res.pop('featureSchemaId') - return res + return self + @model_serializer(mode="wrap") + def model_serializer(self, handler): + res = handler(self) + return feature_serializer(res) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/label.py b/libs/labelbox/src/labelbox/data/annotation_types/label.py index c7a0cb7b8..327a176d1 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/label.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/label.py @@ -19,6 +19,7 @@ from .video import VideoClassificationAnnotation from .video import VideoObjectAnnotation, VideoMaskAnnotation from ..ontology import get_feature_schema_lookup +from pydantic import BaseModel DataType = Union[VideoData, ImageData, TextData, TiledImageData, AudioData, ConversationData, DicomData, DocumentData, HTMLData, @@ -26,7 +27,7 @@ LlmResponseCreationData, GenericDataRowData] -class Label(pydantic_compat.BaseModel): +class Label(BaseModel): """Container for holding data and annotations >>> Label( diff --git a/libs/labelbox/src/labelbox/data/annotation_types/llm_prompt_response/prompt.py b/libs/labelbox/src/labelbox/data/annotation_types/llm_prompt_response/prompt.py index c235526b0..98c0e7a69 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/llm_prompt_response/prompt.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/llm_prompt_response/prompt.py @@ -1,13 +1,9 @@ -from typing import Union - from labelbox.data.annotation_types.base_annotation import BaseAnnotation - from labelbox.data.mixins import ConfidenceMixin, CustomMetricsMixin - -from labelbox import pydantic_compat +from pydantic import BaseModel -class PromptText(ConfidenceMixin, CustomMetricsMixin, pydantic_compat.BaseModel): +class PromptText(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ Prompt text for LLM data generation >>> PromptText(answer = "some text answer", diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py index 79cf22419..ec2ee0581 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py @@ -2,8 +2,9 @@ from typing import Dict, Optional, Any, Union from labelbox import pydantic_compat +from pydantic import confloat -ConfidenceValue = pydantic_compat.confloat(ge=0, le=1) +ConfidenceValue = confloat(ge=0, le=1) MIN_CONFIDENCE_SCORES = 2 MAX_CONFIDENCE_SCORES = 15 diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py index f915e2f25..ec1b01984 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py @@ -1,11 +1,12 @@ from enum import Enum from typing import Tuple, Dict, Union -from labelbox import pydantic_compat +from pydantic import conint from .base import ConfidenceValue, BaseMetric +from typing import Literal -Count = pydantic_compat.conint(ge=0, le=1e10) +Count = conint(ge=0, le=1e10) ConfusionMatrixMetricValue = Tuple[Count, Count, Count, Count] ConfusionMatrixMetricConfidenceValue = Dict[ConfidenceValue, @@ -30,5 +31,5 @@ class ConfusionMatrixMetric(BaseMetric): metric_name: str value: Union[ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue] - aggregation: ConfusionMatrixAggregation = pydantic_compat.Field( - ConfusionMatrixAggregation.CONFUSION_MATRIX, const=True) + aggregation: ConfusionMatrixAggregation = Literal[ + ConfusionMatrixAggregation.CONFUSION_MATRIX] diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 5f1279fd6..2b814a3d9 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -4,8 +4,9 @@ from .base import ConfidenceValue, BaseMetric from labelbox import pydantic_compat +from pydantic import confloat -ScalarMetricValue = pydantic_compat.confloat(ge=0, le=100_000_000) +ScalarMetricValue = confloat(ge=0, le=100_000_000) ScalarMetricConfidenceValue = Dict[ConfidenceValue, ScalarMetricValue] diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py index 77141de06..15b1b015a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py @@ -2,20 +2,21 @@ from labelbox import pydantic_compat from labelbox.utils import _CamelCaseMixin +from pydantic import BaseModel, field_validator -class DocumentTextSelection(_CamelCaseMixin, pydantic_compat.BaseModel): +class DocumentTextSelection(_CamelCaseMixin, BaseModel): token_ids: List[str] group_id: str page: int - @pydantic_compat.validator("page") + @field_validator("page") def validate_page(cls, v): if v < 1: raise ValueError("Page must be greater than 1") return v -class DocumentEntity(_CamelCaseMixin, pydantic_compat.BaseModel): +class DocumentEntity(_CamelCaseMixin, BaseModel): """ Represents a text entity """ text_selections: List[DocumentTextSelection] diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py index 6f410987f..4651ae0e3 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py @@ -1,15 +1,15 @@ from typing import Dict, Any -from labelbox import pydantic_compat +from pydantic import BaseModel, model_validator -class TextEntity(pydantic_compat.BaseModel): +class TextEntity(BaseModel): """ Represents a text entity """ start: int end: int extra: Dict[str, Any] = {} - @pydantic_compat.root_validator + @model_validator(mode="after") def validate_start_end(cls, values): if 'start' in values and 'end' in values: if (isinstance(values['start'], int) and diff --git a/libs/labelbox/src/labelbox/data/annotation_types/relationship.py b/libs/labelbox/src/labelbox/data/annotation_types/relationship.py index db61883d5..27a833830 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/relationship.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/relationship.py @@ -1,9 +1,9 @@ -from labelbox import pydantic_compat +from pydantic import BaseModel from enum import Enum from labelbox.data.annotation_types.annotation import BaseAnnotation, ObjectAnnotation -class Relationship(pydantic_compat.BaseModel): +class Relationship(BaseModel): class Type(Enum): UNIDIRECTIONAL = "unidirectional" diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index 91b258de3..a936a1d2f 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -8,6 +8,7 @@ from labelbox.data.annotation_types.feature import FeatureSchema from labelbox.data.mixins import ConfidenceNotSupportedMixin, CustomMetricsNotSupportedMixin from labelbox.utils import _CamelCaseMixin, is_valid_uri +from pydantic import model_validator, BaseModel, field_validator class VideoClassificationAnnotation(ClassificationAnnotation): @@ -87,12 +88,12 @@ class DICOMObjectAnnotation(VideoObjectAnnotation): group_key: GroupKey -class MaskFrame(_CamelCaseMixin, pydantic_compat.BaseModel): +class MaskFrame(_CamelCaseMixin, BaseModel): index: int instance_uri: Optional[str] = None im_bytes: Optional[bytes] = None - @pydantic_compat.root_validator() + @model_validator(mode="after") def validate_args(cls, values): im_bytes = values.get("im_bytes") instance_uri = values.get("instance_uri") @@ -101,7 +102,7 @@ def validate_args(cls, values): raise ValueError("One of `instance_uri`, `im_bytes` required.") return values - @pydantic_compat.validator("instance_uri") + @field_validator("instance_uri") def validate_uri(cls, v): if not is_valid_uri(v): raise ValueError(f"{v} is not a valid uri") @@ -113,7 +114,7 @@ class MaskInstance(_CamelCaseMixin, FeatureSchema): name: str -class VideoMaskAnnotation(pydantic_compat.BaseModel): +class VideoMaskAnnotation(BaseModel): """Video mask annotation >>> VideoMaskAnnotation( >>> frames=[ diff --git a/libs/labelbox/src/labelbox/data/mixins.py b/libs/labelbox/src/labelbox/data/mixins.py index 36fd91671..0352dba7d 100644 --- a/libs/labelbox/src/labelbox/data/mixins.py +++ b/libs/labelbox/src/labelbox/data/mixins.py @@ -1,14 +1,17 @@ from typing import Optional, List -from labelbox import pydantic_compat +from pydantic import BaseModel, field_validator, model_serializer from labelbox.exceptions import ConfidenceNotSupportedException, CustomMetricsNotSupportedException +from warnings import warn +from labelbox.pydantic_serializers import feature_serializer -class ConfidenceMixin(pydantic_compat.BaseModel): + +class ConfidenceMixin(BaseModel): confidence: Optional[float] = None - @pydantic_compat.validator("confidence") + @field_validator("confidence") def confidence_valid_float(cls, value): if value is None: return value @@ -16,10 +19,10 @@ def confidence_valid_float(cls, value): raise ValueError("must be a number within [0,1] range") return value - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) - if "confidence" in res and res["confidence"] is None: - res.pop("confidence") + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) + res = feature_serializer(res) return res @@ -32,35 +35,35 @@ def __new__(cls, *args, **kwargs): return super().__new__(cls) -class CustomMetric(pydantic_compat.BaseModel): +class CustomMetric(BaseModel): name: str value: float - @pydantic_compat.validator("name") + @field_validator("name") def confidence_valid_float(cls, value): if not isinstance(value, str): raise ValueError("Name must be a string") return value - @pydantic_compat.validator("value") + @field_validator("value") def value_valid_float(cls, value): if not isinstance(value, (int, float)): raise ValueError("Value must be a number") return value -class CustomMetricsMixin(pydantic_compat.BaseModel): +class CustomMetricsMixin(BaseModel): custom_metrics: Optional[List[CustomMetric]] = None - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) - + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) if "customMetrics" in res and res["customMetrics"] is None: res.pop("customMetrics") - + if "custom_metrics" in res and res["custom_metrics"] is None: res.pop("custom_metrics") - + return res diff --git a/libs/labelbox/src/labelbox/data/ontology.py b/libs/labelbox/src/labelbox/data/ontology.py index 56850b966..f19208873 100644 --- a/libs/labelbox/src/labelbox/data/ontology.py +++ b/libs/labelbox/src/labelbox/data/ontology.py @@ -1,7 +1,7 @@ from typing import Dict, List, Tuple, Union from labelbox.schema import ontology -from .annotation_types import (Text, Dropdown, Checklist, Radio, +from .annotation_types import (Text, Checklist, Radio, ClassificationAnnotation, ObjectAnnotation, Mask, Point, Line, Polygon, Rectangle, TextEntity) @@ -46,11 +46,11 @@ def _get_options(annotation: ClassificationAnnotation, answers = [annotation.value.answer] elif isinstance(annotation.value, Text): return existing_options - elif isinstance(annotation.value, (Checklist, Dropdown)): + elif isinstance(annotation.value, (Checklist)): answers = annotation.value.answer else: raise TypeError( - f"Expected one of Radio, Text, Checklist, Dropdown. Found {type(annotation.value)}" + f"Expected one of Radio, Text, Checklist. Found {type(annotation.value)}" ) option_names = {option.value for option in existing_options} @@ -123,13 +123,12 @@ def tool_mapping( def classification_mapping( - annotation) -> Union[Text, Checklist, Radio, Dropdown]: + annotation) -> Union[Text, Checklist, Radio]: classification_types = ontology.Classification.Type mapping = { Text: classification_types.TEXT, Checklist: classification_types.CHECKLIST, Radio: classification_types.RADIO, - Dropdown: classification_types.DROPDOWN } result = mapping.get(type(annotation.value)) if result is None: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index 2a9186e02..f6773a9ce 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -4,13 +4,14 @@ from labelbox.utils import _CamelCaseMixin, is_exactly_one_set from labelbox import pydantic_compat from ...annotation_types.types import Cuid +from pydantic import field_validator, model_validator class DataRow(_CamelCaseMixin): id: str = None global_key: str = None - @pydantic_compat.root_validator() + @model_validator(mode="after") def must_set_one(cls, values): if not is_exactly_one_set(values.get('id'), values.get('global_key')): raise ValueError("Must set either id or global_key") @@ -21,13 +22,13 @@ class NDJsonBase(_CamelCaseMixin): uuid: str = None data_row: DataRow - @pydantic_compat.validator('uuid', pre=True, always=True) + @field_validator('uuid', mode="before") def set_id(cls, v): return v or str(uuid4()) def dict(self, *args, **kwargs): """ Pop missing id or missing globalKey from dataRow """ - res = super().dict(*args, **kwargs) + res = super().model_dump(*args, **kwargs) if not self.data_row.id: res['dataRow'].pop('id') if not self.data_row.global_key: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index 46b8fc91f..edd8c7343 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -11,6 +11,7 @@ from ...annotation_types.classification.classification import ClassificationAnswer, Dropdown, Text, Checklist, Radio from ...annotation_types.types import Cuid from ...annotation_types.data import TextData, VideoData, ImageData +from pydantic import model_validator, Field, BaseModel class NDAnswer(ConfidenceMixin, CustomMetricsMixin): @@ -18,7 +19,7 @@ class NDAnswer(ConfidenceMixin, CustomMetricsMixin): schema_id: Optional[Cuid] = None classifications: Optional[List['NDSubclassificationType']] = [] - @pydantic_compat.root_validator() + @model_validator(mode="after") def must_set_one(cls, values): if ('schema_id' not in values or values['schema_id'] is None) and ('name' not in values or values['name'] is None): @@ -26,7 +27,7 @@ def must_set_one(cls, values): return values def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + res = super().model_dump(*args, **kwargs) if 'name' in res and res['name'] is None: res.pop('name') if 'schemaId' in res and res['schemaId'] is None: @@ -44,17 +45,17 @@ class Config: alias_generator = camel_case -class FrameLocation(pydantic_compat.BaseModel): +class FrameLocation(BaseModel): end: int start: int -class VideoSupported(pydantic_compat.BaseModel): +class VideoSupported(BaseModel): # Note that frames are only allowed as top level inferences for video frames: Optional[List[FrameLocation]] = None def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + res = super().model_dump(*args, **kwargs) # This means these are no video frames .. if self.frames is None: res.pop('frames') @@ -82,7 +83,7 @@ def from_common(cls, text: Text, name: str, class NDChecklistSubclass(NDAnswer): - answer: List[NDAnswer] = pydantic_compat.Field(..., alias='answers') + answer: List[NDAnswer] = Field(..., alias='answers') def to_common(self) -> Checklist: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index 9d34c451b..bb487be25 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -24,6 +24,7 @@ from .objects import NDObject, NDObjectType, NDSegments, NDDicomSegments, NDVideoMasks, NDDicomMasks from .relationship import NDRelationship from .base import DataRow +from pydantic import BaseModel AnnotationType = Union[NDObjectType, NDClassificationType, NDPromptClassificationType, NDConfusionMatrixMetric, NDScalarMetric, NDDicomSegments, @@ -31,16 +32,16 @@ NDPromptText] -class NDLabel(pydantic_compat.BaseModel): +class NDLabel(BaseModel): annotations: List[AnnotationType] - class _Relationship(pydantic_compat.BaseModel): + class _Relationship(BaseModel): """This object holds information about the relationship""" ndjson: NDRelationship source: str target: str - class _AnnotationGroup(pydantic_compat.BaseModel): + class _AnnotationGroup(BaseModel): """Stores all the annotations and relationships per datarow""" data_row: DataRow = None ndjson_annotations: Dict[str, AnnotationType] = {} diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py index 5abbf2761..b918604b5 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py @@ -19,7 +19,7 @@ class Config: use_enum_values = True def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + res = super().model_dump(*args, **kwargs) for field in ['featureName', 'subclassName']: if res[field] is None: res.pop(field) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index fd13a6bf6..eb7fa73f4 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -21,27 +21,28 @@ from ...annotation_types.video import VideoMaskAnnotation, DICOMMaskAnnotation, MaskFrame, MaskInstance from .classification import NDClassification, NDSubclassification, NDSubclassificationType from .base import DataRow, NDAnnotation, NDJsonBase +from pydantic import BaseModel class NDBaseObject(NDAnnotation): classifications: List[NDSubclassificationType] = [] -class VideoSupported(pydantic_compat.BaseModel): +class VideoSupported(BaseModel): # support for video for objects are per-frame basis frame: int -class DicomSupported(pydantic_compat.BaseModel): +class DicomSupported(BaseModel): group_key: str -class _Point(pydantic_compat.BaseModel): +class _Point(BaseModel): x: float y: float -class Bbox(pydantic_compat.BaseModel): +class Bbox(BaseModel): top: float left: float height: float @@ -328,7 +329,7 @@ def from_common( classifications=classifications) -class NDSegment(pydantic_compat.BaseModel): +class NDSegment(BaseModel): keyframes: List[Union[NDFrameRectangle, NDFramePoint, NDFrameLine]] @staticmethod @@ -512,7 +513,7 @@ def from_common( custom_metrics=custom_metrics) -class NDVideoMasksFramesInstances(pydantic_compat.BaseModel): +class NDVideoMasksFramesInstances(BaseModel): frames: List[MaskFrame] instances: List[MaskInstance] diff --git a/libs/labelbox/src/labelbox/pydantic_serializers.py b/libs/labelbox/src/labelbox/pydantic_serializers.py new file mode 100644 index 000000000..c2f2ac630 --- /dev/null +++ b/libs/labelbox/src/labelbox/pydantic_serializers.py @@ -0,0 +1,21 @@ +from typing import Dict + +def feature_serializer(res: Dict) -> Dict: + """Used as a with custom model serializer for pydantics. This ensures backwards compatibility since pydantic V1 allowed you to override Dict method. This method needs to be used for all base classes and sub classes. We should look at getting this removed.""" + if "customMetrics" in res and res["customMetrics"] is None: + res.pop("customMetrics") + if "custom_metrics" in res and res["custom_metrics"] is None: + res.pop("custom_metrics") + if "keyframe" in res and res["keyframe"] == None: + res.pop("keyframe") + if "classifications" in res and res["classifications"] == []: + res.pop("classifications") + if "confidence" in res and res["confidence"] is None: + res.pop("confidence") + if 'name' in res and res['name'] is None: + res.pop('name') + if 'featureSchemaId' in res and res['featureSchemaId'] is None: + res.pop('featureSchemaId') + + return res + \ No newline at end of file diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 3a6b58706..f45f2562f 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -10,6 +10,7 @@ from labelbox import pydantic_compat from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey +from pydantic import BaseModel, constr from labelbox.schema.ontology import SchemaId from labelbox.utils import _CamelCaseMixin, camel_case, format_iso_datetime, format_iso_from_string @@ -45,7 +46,7 @@ class DataRowMetadataSchema(pydantic_compat.BaseModel): # Metadata base class -class DataRowMetadataField(_CamelCaseMixin): +class DataRowMetadataField(BaseModel): # One of `schema_id` or `name` must be provided. If `schema_id` is not provided, it is # inferred from `name` schema_id: Optional[SchemaId] = None @@ -124,15 +125,15 @@ def dict(self, *args, **kwargs): class _UpsertCustomMetadataSchemaEnumOptionInput(_CamelCaseMixin): id: Optional[SchemaId] - name: pydantic_compat.constr(strip_whitespace=True, - min_length=1, - max_length=100) + name: constr(strip_whitespace=True, + min_length=1, + max_length=100) kind: str class _UpsertCustomMetadataSchemaInput(_CamelCaseMixin): id: Optional[SchemaId] - name: pydantic_compat.constr(strip_whitespace=True, + name: constr(strip_whitespace=True, min_length=1, max_length=100) kind: str diff --git a/libs/labelbox/src/labelbox/schema/export_task.py b/libs/labelbox/src/labelbox/schema/export_task.py index 06715748c..0ea75646f 100644 --- a/libs/labelbox/src/labelbox/schema/export_task.py +++ b/libs/labelbox/src/labelbox/schema/export_task.py @@ -27,6 +27,7 @@ from labelbox.schema.task import Task from labelbox.utils import _CamelCaseMixin +from pydantic import BaseModel if TYPE_CHECKING: from labelbox import Client @@ -41,19 +42,19 @@ class StreamType(Enum): ERRORS = "ERRORS" -class Range(_CamelCaseMixin, pydantic_compat.BaseModel): # pylint: disable=too-few-public-methods +class Range(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods """Represents a range.""" start: int end: int -class _MetadataHeader(_CamelCaseMixin, pydantic_compat.BaseModel): # pylint: disable=too-few-public-methods +class _MetadataHeader(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods total_size: int total_lines: int -class _MetadataFileInfo(_CamelCaseMixin, pydantic_compat.BaseModel): # pylint: disable=too-few-public-methods +class _MetadataFileInfo(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods offsets: Range lines: Range file: str diff --git a/libs/labelbox/src/labelbox/schema/foundry/app.py b/libs/labelbox/src/labelbox/schema/foundry/app.py index eead39518..7441117ac 100644 --- a/libs/labelbox/src/labelbox/schema/foundry/app.py +++ b/libs/labelbox/src/labelbox/schema/foundry/app.py @@ -1,11 +1,9 @@ from labelbox.utils import _CamelCaseMixin - -from labelbox import pydantic_compat - from typing import Any, Dict, Optional +from pydantic import BaseModel -class App(_CamelCaseMixin, pydantic_compat.BaseModel): +class App(_CamelCaseMixin, BaseModel): id: Optional[str] model_id: str name: str @@ -20,4 +18,4 @@ def type_name(cls): return "App" -APP_FIELD_NAMES = list(App.schema()['properties'].keys()) +APP_FIELD_NAMES = list(App.model_json_schema()['properties'].keys()) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 985405059..6bfb0f650 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -11,10 +11,11 @@ from labelbox.orm.model import Field, Relationship from labelbox import pydantic_compat import json +from pydantic import constr FeatureSchemaId: Type[str] = pydantic_compat.constr(min_length=25, max_length=25) -SchemaId: Type[str] = pydantic_compat.constr(min_length=25, max_length=25) +SchemaId: Type[str] = constr(min_length=25, max_length=25) class DeleteFeatureFromOntologyResult: diff --git a/libs/labelbox/src/labelbox/utils.py b/libs/labelbox/src/labelbox/utils.py index dc285e60b..ce0f3c210 100644 --- a/libs/labelbox/src/labelbox/utils.py +++ b/libs/labelbox/src/labelbox/utils.py @@ -6,6 +6,7 @@ from dateutil.utils import default_tzinfo from urllib.parse import urlparse +from pydantic import BaseModel from labelbox import pydantic_compat UPPERCASE_COMPONENTS = ['uri', 'rgb'] @@ -60,7 +61,7 @@ def is_valid_uri(uri): return False -class _CamelCaseMixin(pydantic_compat.BaseModel): +class _CamelCaseMixin(BaseModel): class Config: allow_population_by_field_name = True diff --git a/libs/labelbox/tests/data/annotation_types/classification/test_classification.py b/libs/labelbox/tests/data/annotation_types/classification/test_classification.py index 11a3a0514..9a4ea0d39 100644 --- a/libs/labelbox/tests/data/annotation_types/classification/test_classification.py +++ b/libs/labelbox/tests/data/annotation_types/classification/test_classification.py @@ -1,14 +1,14 @@ import pytest from labelbox.data.annotation_types import (Checklist, ClassificationAnswer, - Dropdown, Radio, Text, + Radio, Text, ClassificationAnnotation) -from labelbox import pydantic_compat +from pydantic import ValidationError def test_classification_answer(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): ClassificationAnswer() feature_schema_id = "schema_id" @@ -22,7 +22,7 @@ def test_classification_answer(): assert answer.feature_schema_id is None assert answer.name == name assert answer.confidence == confidence - assert answer.custom_metrics == custom_metrics + assert [answer.custom_metrics[0].model_dump()] == custom_metrics answer = ClassificationAnswer(feature_schema_id=feature_schema_id, name=name) @@ -35,9 +35,9 @@ def test_classification(): answer = "1234" classification = ClassificationAnnotation(value=Text(answer=answer), name="a classification") - assert classification.dict()['value']['answer'] == answer + assert classification.model_dump()['value']['answer'] == answer - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): ClassificationAnnotation() @@ -45,12 +45,13 @@ def test_subclass(): answer = "1234" feature_schema_id = "11232" name = "my_feature" - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): # Should have feature schema info classification = ClassificationAnnotation(value=Text(answer=answer)) classification = ClassificationAnnotation(value=Text(answer=answer), name=name) - assert classification.dict() == { + print(classification.model_dump()) + assert classification.model_dump() == { 'name': name, 'feature_schema_id': None, 'extra': {}, @@ -63,7 +64,7 @@ def test_subclass(): value=Text(answer=answer), name=name, feature_schema_id=feature_schema_id) - assert classification.dict() == { + assert classification.model_dump() == { 'name': None, 'feature_schema_id': feature_schema_id, 'extra': {}, @@ -77,7 +78,7 @@ def test_subclass(): value=Text(answer=answer), feature_schema_id=feature_schema_id, name=name) - assert classification.dict() == { + assert classification.model_dump() == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, @@ -98,14 +99,15 @@ def test_radio(): feature_schema_id = "feature_schema_id" name = "my_feature" - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): classification = ClassificationAnnotation(value=Radio( answer=answer.name)) - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): classification = Radio(answer=[answer]) - classification = Radio(answer=answer,) - assert classification.dict() == { + classification = Radio(answer=answer) + + assert classification.model_dump() == { 'answer': { 'name': answer.name, 'feature_schema_id': None, @@ -125,7 +127,7 @@ def test_radio(): 'name': 'metric1', 'value': 0.99 }]) - assert classification.dict() == { + assert classification.model_dump() == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, @@ -159,14 +161,14 @@ def test_checklist(): feature_schema_id = "feature_schema_id" name = "my_feature" - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): classification = Checklist(answer=answer.name) - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): classification = Checklist(answer=answer) classification = Checklist(answer=[answer]) - assert classification.dict() == { + assert classification.model_dump() == { 'answer': [{ 'name': answer.name, 'feature_schema_id': None, @@ -183,7 +185,7 @@ def test_checklist(): feature_schema_id=feature_schema_id, name=name, ) - assert classification.dict() == { + assert classification.model_dump() == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, @@ -201,43 +203,3 @@ def test_checklist(): }, 'message_id': None, } - - -def test_dropdown(): - answer = ClassificationAnswer(name="1", confidence=1) - feature_schema_id = "feature_schema_id" - name = "my_feature" - - with pytest.raises(pydantic_compat.ValidationError): - classification = ClassificationAnnotation( - value=Dropdown(answer=answer.name), name="test") - - with pytest.raises(pydantic_compat.ValidationError): - classification = Dropdown(answer=answer) - classification = Dropdown(answer=[answer]) - assert classification.dict() == { - 'answer': [{ - 'name': '1', - 'feature_schema_id': None, - 'extra': {}, - 'confidence': 1 - }] - } - classification = ClassificationAnnotation( - value=Dropdown(answer=[answer]), - feature_schema_id=feature_schema_id, - name=name) - assert classification.dict() == { - 'name': name, - 'feature_schema_id': feature_schema_id, - 'extra': {}, - 'value': { - 'answer': [{ - 'name': answer.name, - 'feature_schema_id': None, - 'confidence': 1, - 'extra': {} - }] - }, - 'message_id': None, - } From 070600583506038d0d60a0fe544c0f3264862e46 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:49:52 -0500 Subject: [PATCH 02/34] fixed data row metadata tests --- libs/labelbox/pyproject.toml | 2 +- .../src/labelbox/schema/data_row_metadata.py | 35 +++++++++---------- .../schema/internal/data_row_upsert_item.py | 4 +-- libs/labelbox/src/labelbox/schema/ontology.py | 5 +-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index 35865e6f5..fc09cf6ff 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -85,7 +85,7 @@ unit = "pytest tests/unit" # LABELBOX_TEST_ENVIRON="ephemeral" \ # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ -integration = { cmd = "pytest tests/integration" } +integration = { cmd = "pytest tests/integration/test_data_rows.py" } data = { cmd = "pytest tests/data" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index f45f2562f..63679cf8d 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -6,11 +6,12 @@ import warnings from typing import List, Optional, Dict, Union, Callable, Type, Any, Generator, overload +from typing_extensions import Annotated from labelbox import pydantic_compat from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey -from pydantic import BaseModel, constr +from pydantic import BaseModel, Field, StringConstraints from labelbox.schema.ontology import SchemaId from labelbox.utils import _CamelCaseMixin, camel_case, format_iso_datetime, format_iso_from_string @@ -49,9 +50,10 @@ class DataRowMetadataSchema(pydantic_compat.BaseModel): class DataRowMetadataField(BaseModel): # One of `schema_id` or `name` must be provided. If `schema_id` is not provided, it is # inferred from `name` - schema_id: Optional[SchemaId] = None + # schema id alias to json key name for pydantic v2 support + schema_id: Optional[SchemaId] = Field(default=None, serialization_alias="schemaId") name: Optional[str] = None - # value is of type `Any` so that we do not improperly coerce the value to the wrong tpye + # value is of type `Any` so that we do not improperly coerce the value to the wrong type # Additional validation is performed before upload using the schema information value: Any @@ -125,19 +127,18 @@ def dict(self, *args, **kwargs): class _UpsertCustomMetadataSchemaEnumOptionInput(_CamelCaseMixin): id: Optional[SchemaId] - name: constr(strip_whitespace=True, - min_length=1, - max_length=100) + name: Annotated[str, StringConstraints(strip_whitespace=True, + min_length=1, + max_length=100)] kind: str - class _UpsertCustomMetadataSchemaInput(_CamelCaseMixin): - id: Optional[SchemaId] - name: constr(strip_whitespace=True, - min_length=1, - max_length=100) + id: Optional[SchemaId] = None + name: Annotated[str, StringConstraints(strip_whitespace=True, + min_length=1, + max_length=100)] kind: str - options: Optional[List[_UpsertCustomMetadataSchemaEnumOptionInput]] + options: Optional[List[_UpsertCustomMetadataSchemaEnumOptionInput]] = None class DataRowMetadataOntology: @@ -779,7 +780,7 @@ def _convert_metadata_field(metadata_field): metadata_fields = [_convert_metadata_field(m) for m in metadata_fields] parsed_metadata = list( chain.from_iterable(self._parse_upsert(m) for m in metadata_fields)) - return [m.dict(by_alias=True) for m in parsed_metadata] + return [m.model_dump(by_alias=True) for m in parsed_metadata] def _upsert_schema( self, upsert_schema: _UpsertCustomMetadataSchemaInput @@ -863,7 +864,6 @@ def _parse_upsert( if data_row_id: error_str += f", data_row_id='{data_row_id}'" raise ValueError(f"{error_str}. Reason: {e}") - return [_UpsertDataRowMetadataInput(**p) for p in parsed] def _validate_delete(self, delete: DeleteDataRowMetadata): @@ -934,14 +934,14 @@ def _validate_parse_embedding( else: raise ValueError( f"Expected a list for embedding. Found {type(field.value)}") - return [field.dict(by_alias=True)] + return [field.model_dump(by_alias=True)] def _validate_parse_number( field: DataRowMetadataField ) -> List[Dict[str, Union[SchemaId, str, float, int]]]: field.value = float(field.value) - return [field.dict(by_alias=True)] + return [field.model_dump(by_alias=True)] def _validate_parse_datetime( @@ -969,8 +969,7 @@ def _validate_parse_text( if len(field.value) > String.max_length: raise ValueError( f"String fields cannot exceed {String.max_length} characters.") - - return [field.dict(by_alias=True)] + return [field.model_dump(by_alias=True)] def _validate_enum_parse( diff --git a/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py b/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py index 5ae001983..d3cc60483 100644 --- a/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py +++ b/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py @@ -4,11 +4,11 @@ from labelbox.pydantic_compat import BaseModel from labelbox.schema.identifiable import UniqueId, GlobalKey -from labelbox import pydantic_compat from labelbox.schema.data_row import DataRow +from pydantic import BaseModel -class DataRowItemBase(ABC, pydantic_compat.BaseModel): +class DataRowItemBase(ABC, BaseModel): """ Base class for creating payloads for upsert operations. """ diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 6bfb0f650..152d5a5a8 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -4,6 +4,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import Any, Dict, List, Optional, Union, Type +from typing_extensions import Annotated import warnings from labelbox.exceptions import InconsistentOntologyException @@ -11,11 +12,11 @@ from labelbox.orm.model import Field, Relationship from labelbox import pydantic_compat import json -from pydantic import constr +from pydantic import StringConstraints FeatureSchemaId: Type[str] = pydantic_compat.constr(min_length=25, max_length=25) -SchemaId: Type[str] = constr(min_length=25, max_length=25) +SchemaId: Type[str] = Annotated[str, StringConstraints(min_length=25, max_length=25)] class DeleteFeatureFromOntologyResult: From b174be76357cf43bb411f2b059aaa18cbebf1894 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:00:03 -0500 Subject: [PATCH 03/34] fixed linting test --- libs/labelbox/src/labelbox/schema/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/project.py b/libs/labelbox/src/labelbox/schema/project.py index 0993ff048..2027877e2 100644 --- a/libs/labelbox/src/labelbox/schema/project.py +++ b/libs/labelbox/src/labelbox/schema/project.py @@ -879,7 +879,7 @@ def create_batch( name: str, data_rows: Optional[List[Union[str, DataRow]]] = None, priority: int = 5, - consensus_settings: Optional[Dict[str, float]] = None, + consensus_settings: Optional[Dict[str, Any]] = None, global_keys: Optional[List[str]] = None, ): """ @@ -951,7 +951,7 @@ def create_batches( data_rows: Optional[List[Union[str, DataRow]]] = None, global_keys: Optional[List[str]] = None, priority: int = 5, - consensus_settings: Optional[Dict[str, float]] = None, + consensus_settings: Optional[Dict[str, Any]] = None, ) -> CreateBatchesTask: """ Creates batches for a project from a list of data rows. One of `global_keys` or `data_rows` must be provided, @@ -1032,7 +1032,7 @@ def create_batches_from_dataset( dataset_id: str, priority: int = 5, consensus_settings: Optional[Dict[str, - float]] = None) -> CreateBatchesTask: + Any]] = None) -> CreateBatchesTask: """ Creates batches for a project from a dataset, selecting only the data rows that are not already added to the project. When the dataset contains more than 100k data rows and multiple batches are needed, the specific batch From db56b1fca040ab83db7bbcc8ee3bd879576830f7 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 12:25:29 -0500 Subject: [PATCH 04/34] more tests fixed --- libs/labelbox/src/labelbox/schema/export_task.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/export_task.py b/libs/labelbox/src/labelbox/schema/export_task.py index 0ea75646f..8752d0618 100644 --- a/libs/labelbox/src/labelbox/schema/export_task.py +++ b/libs/labelbox/src/labelbox/schema/export_task.py @@ -27,7 +27,7 @@ from labelbox.schema.task import Task from labelbox.utils import _CamelCaseMixin -from pydantic import BaseModel +from pydantic import BaseModel, Field if TYPE_CHECKING: from labelbox import Client @@ -50,8 +50,8 @@ class Range(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-metho class _MetadataHeader(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods - total_size: int - total_lines: int + total_size: int = Field(validation_alias="total_size") + total_lines: int = Field(validation_alias="total_lines") class _MetadataFileInfo(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods From caa8eab62a44f7a7cc112dbda4fa3b822586752e Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 13:08:30 -0500 Subject: [PATCH 05/34] fixed another set up tests --- libs/labelbox/pyproject.toml | 4 ++-- .../data/annotation_types/data/base_data.py | 4 ++-- .../data/generic_data_row_data.py | 4 ++-- .../data/annotation_types/data/raster.py | 6 +++--- .../data/annotation_types/data/tiled_image.py | 7 ++++--- .../annotation_types/geometry/geometry.py | 4 ++-- .../labelbox/data/annotation_types/label.py | 20 +++++++++---------- .../labelbox/data/annotation_types/types.py | 6 +++--- 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index fc09cf6ff..da8a805ea 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -85,8 +85,8 @@ unit = "pytest tests/unit" # LABELBOX_TEST_ENVIRON="ephemeral" \ # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ -integration = { cmd = "pytest tests/integration/test_data_rows.py" } -data = { cmd = "pytest tests/data" } +integration = { cmd = "pytest tests/integration" } +data = { cmd = "pytest tests/unit/test_label_data_type.py" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/base_data.py b/libs/labelbox/src/labelbox/data/annotation_types/data/base_data.py index ab0dd1e53..2ccda34c3 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/base_data.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/base_data.py @@ -1,10 +1,10 @@ from abc import ABC from typing import Optional, Dict, List, Any -from labelbox import pydantic_compat +from pydantic import BaseModel -class BaseData(pydantic_compat.BaseModel, ABC): +class BaseData(BaseModel, ABC): """ Base class for objects representing data. This class shouldn't directly be used diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py index c4a68add6..58eb07b9e 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py @@ -1,8 +1,8 @@ from typing import Callable, Literal, Optional -from labelbox import pydantic_compat from labelbox.data.annotation_types.data.base_data import BaseData from labelbox.utils import _NoCoercionMixin +from pydantic import model_validator class GenericDataRowData(BaseData, _NoCoercionMixin): @@ -14,7 +14,7 @@ class GenericDataRowData(BaseData, _NoCoercionMixin): def create_url(self, signer: Callable[[bytes], str]) -> Optional[str]: return self.url - @pydantic_compat.root_validator(pre=True) + @model_validator(mode="before") def validate_one_datarow_key_present(cls, data): keys = ['external_id', 'global_key', 'uid'] count = sum([key in data for key in keys]) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index 94b8a2a7e..498cf39a9 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -9,13 +9,13 @@ import requests import numpy as np -from labelbox import pydantic_compat +from pydantic import BaseModel, model_validator from labelbox.exceptions import InternalServerError from .base_data import BaseData from ..types import TypedArray -class RasterData(pydantic_compat.BaseModel, ABC): +class RasterData(BaseModel, ABC): """Represents an image or segmentation mask. """ im_bytes: Optional[bytes] = None @@ -155,7 +155,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> str: "One of url, im_bytes, file_path, arr must not be None.") return self.url - @pydantic_compat.root_validator() + @model_validator(mode="after") def validate_args(cls, values): file_path = values.get("file_path") im_bytes = values.get("im_bytes") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py index 6a3bd6988..fae0d426a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py @@ -17,6 +17,7 @@ from labelbox.data.annotation_types import Rectangle, Point, Line, Polygon from .base_data import BaseData from .raster import RasterData +from pydantic import BaseModel, field_validator, model_validator VALID_LAT_RANGE = range(-90, 90) VALID_LNG_RANGE = range(-180, 180) @@ -40,7 +41,7 @@ class EPSG(Enum): EPSG3857 = 3857 -class TiledBounds(pydantic_compat.BaseModel): +class TiledBounds(BaseModel): """ Bounds for a tiled image asset related to the relevant epsg. Bounds should be Point objects. @@ -54,7 +55,7 @@ class TiledBounds(pydantic_compat.BaseModel): epsg: EPSG bounds: List[Point] - @pydantic_compat.validator('bounds') + @field_validator('bounds') def validate_bounds_not_equal(cls, bounds): first_bound = bounds[0] second_bound = bounds[1] @@ -66,7 +67,7 @@ def validate_bounds_not_equal(cls, bounds): return bounds #validate bounds are within lat,lng range if they are EPSG4326 - @pydantic_compat.root_validator + @model_validator(mode="after") def validate_bounds_lat_lng(cls, values): epsg = values.get('epsg') bounds = values.get('bounds') diff --git a/libs/labelbox/src/labelbox/data/annotation_types/geometry/geometry.py b/libs/labelbox/src/labelbox/data/annotation_types/geometry/geometry.py index 2394f011f..acdfa94c2 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/geometry/geometry.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/geometry/geometry.py @@ -3,12 +3,12 @@ import geojson import numpy as np -from labelbox import pydantic_compat from shapely import geometry as geom +from pydantic import BaseModel -class Geometry(pydantic_compat.BaseModel, ABC): +class Geometry(BaseModel, ABC): """Abstract base class for geometry objects """ extra: Dict[str, Any] = {} diff --git a/libs/labelbox/src/labelbox/data/annotation_types/label.py b/libs/labelbox/src/labelbox/data/annotation_types/label.py index 327a176d1..37c909cd3 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/label.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/label.py @@ -2,8 +2,6 @@ from typing import Any, Callable, Dict, List, Union, Optional import warnings -from labelbox import pydantic_compat - import labelbox from labelbox.data.annotation_types.data.generic_data_row_data import GenericDataRowData from labelbox.data.annotation_types.data.tiled_image import TiledImageData @@ -19,7 +17,7 @@ from .video import VideoClassificationAnnotation from .video import VideoObjectAnnotation, VideoMaskAnnotation from ..ontology import get_feature_schema_lookup -from pydantic import BaseModel +from pydantic import BaseModel, field_validator DataType = Union[VideoData, ImageData, TextData, TiledImageData, AudioData, ConversationData, DicomData, DocumentData, HTMLData, @@ -56,15 +54,15 @@ class Label(BaseModel): extra: Dict[str, Any] = {} is_benchmark_reference: Optional[bool] = False - @pydantic_compat.root_validator(pre=True) - def validate_data(cls, label): - if isinstance(label.get("data"), Dict): - label["data"]["class_name"] = "GenericDataRowData" + @field_validator("data", mode="before") + def validate_data(cls, data): + if isinstance(data, Dict): + data["class_name"] = "GenericDataRowData" else: warnings.warn( - f"Using {type(label['data']).__name__} class for label.data is deprecated. " + f"Using {type(data).__name__} class for label.data is deprecated. " "Use a dict or an instance of GenericDataRowData instead.") - return label + return data def object_annotations(self) -> List[ObjectAnnotation]: return self._get_annotations_by_type(ObjectAnnotation) @@ -204,11 +202,11 @@ def _assign_option(self, classification: ClassificationAnnotation, f"Unexpected type for answer found. {type(classification.value.answer)}" ) - @pydantic_compat.validator("annotations", pre=True) + @field_validator("annotations", mode="before") def validate_union(cls, value): supported = tuple([ field.type_ - for field in cls.__fields__['annotations'].sub_fields[0].sub_fields + for field in cls.model_fields['annotations'].sub_fields[0].sub_fields ]) if not isinstance(value, list): raise TypeError(f"Annotations must be a list. Found {type(value)}") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/types.py b/libs/labelbox/src/labelbox/data/annotation_types/types.py index 3305462b1..c1dd78680 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/types.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/types.py @@ -5,9 +5,9 @@ from packaging import version import numpy as np -from labelbox import pydantic_compat +from pydantic import StringConstraints, Field -Cuid = Annotated[str, pydantic_compat.Field(min_length=25, max_length=25)] +Cuid = Annotated[str, StringConstraints(min_length=25, max_length=25)] DType = TypeVar('DType') DShape = TypeVar('DShape') @@ -20,7 +20,7 @@ def __get_validators__(cls): yield cls.validate @classmethod - def validate(cls, val, field: pydantic_compat.ModelField): + def validate(cls, val, field: Field): if not isinstance(val, np.ndarray): raise TypeError(f"Expected numpy array. Found {type(val)}") From f408acdd0faa38d5c4c5776139924e4967665af5 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 13:25:00 -0500 Subject: [PATCH 06/34] fixed more tests --- libs/labelbox/pyproject.toml | 2 +- .../src/labelbox/schema/data_row_metadata.py | 32 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index da8a805ea..b4a86d0ff 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -86,7 +86,7 @@ unit = "pytest tests/unit" # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/unit/test_label_data_type.py" } +data = { cmd = "pytest tests/unit/test_unit_delete_batch_data_row_metadata.py" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 63679cf8d..a7af2c784 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -8,10 +8,10 @@ from typing import List, Optional, Dict, Union, Callable, Type, Any, Generator, overload from typing_extensions import Annotated -from labelbox import pydantic_compat from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey -from pydantic import BaseModel, Field, StringConstraints +from pydantic import BaseModel, Field, StringConstraints, ConfigDict, AliasGenerator, model_serializer, conlist +from pydantic.alias_generators import to_camel from labelbox.schema.ontology import SchemaId from labelbox.utils import _CamelCaseMixin, camel_case, format_iso_datetime, format_iso_from_string @@ -27,23 +27,23 @@ class DataRowMetadataKind(Enum): # Metadata schema -class DataRowMetadataSchema(pydantic_compat.BaseModel): +class DataRowMetadataSchema(BaseModel): uid: SchemaId - name: pydantic_compat.constr(strip_whitespace=True, - min_length=1, - max_length=100) + name: str = Annotated[str, StringConstraints(strip_whitespace=True, + min_length=1, + max_length=100)] reserved: bool kind: DataRowMetadataKind options: Optional[List["DataRowMetadataSchema"]] parent: Optional[SchemaId] -DataRowMetadataSchema.update_forward_refs() +DataRowMetadataSchema.model_rebuild() -Embedding: Type[List[float]] = pydantic_compat.conlist(float, - min_items=128, - max_items=128) -String: Type[str] = pydantic_compat.constr(max_length=4096) +Embedding: Type[List[float]] = conlist(float, + min_length=128, + max_length=128) +String: Type[str] = Annotated[str, StringConstraints(max_length=4096)] # Metadata base class @@ -99,13 +99,11 @@ class _UpsertBatchDataRowMetadata(_CamelCaseMixin): class _DeleteBatchDataRowMetadata(_CamelCaseMixin): data_row_identifier: Union[UniqueId, GlobalKey] schema_ids: List[SchemaId] + model_config = ConfigDict(arbitrary_types_allowed=True, alias_generator=AliasGenerator(serialization_alias=to_camel)) - class Config: - arbitrary_types_allowed = True - alias_generator = camel_case - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) if 'data_row_identifier' in res.keys(): key = 'data_row_identifier' id_type_key = 'id_type' From 415c1d9a4bf7d7b20f823d1c79cd079eea13b2ec Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 13:49:54 -0500 Subject: [PATCH 07/34] finished unit tests --- libs/labelbox/pyproject.toml | 4 ++-- libs/labelbox/src/labelbox/schema/data_row_metadata.py | 4 ++-- libs/labelbox/src/labelbox/schema/export_task.py | 7 +++---- libs/labelbox/src/labelbox/utils.py | 9 +++------ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index b4a86d0ff..11de0eb84 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -85,8 +85,8 @@ unit = "pytest tests/unit" # LABELBOX_TEST_ENVIRON="ephemeral" \ # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ -integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/unit/test_unit_delete_batch_data_row_metadata.py" } +integration = { cmd = "pytest tests/integration/test_send_to_annotate.py" } +data = { cmd = "pytest tests/unit" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index a7af2c784..0ecfa45c8 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -34,8 +34,8 @@ class DataRowMetadataSchema(BaseModel): max_length=100)] reserved: bool kind: DataRowMetadataKind - options: Optional[List["DataRowMetadataSchema"]] - parent: Optional[SchemaId] + options: Optional[List["DataRowMetadataSchema"]] = None + parent: Optional[SchemaId] = None DataRowMetadataSchema.model_rebuild() diff --git a/libs/labelbox/src/labelbox/schema/export_task.py b/libs/labelbox/src/labelbox/schema/export_task.py index 8752d0618..66c1b66d8 100644 --- a/libs/labelbox/src/labelbox/schema/export_task.py +++ b/libs/labelbox/src/labelbox/schema/export_task.py @@ -23,11 +23,10 @@ import warnings import tempfile import os -from labelbox import pydantic_compat from labelbox.schema.task import Task from labelbox.utils import _CamelCaseMixin -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, AliasChoices if TYPE_CHECKING: from labelbox import Client @@ -50,8 +49,8 @@ class Range(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-metho class _MetadataHeader(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods - total_size: int = Field(validation_alias="total_size") - total_lines: int = Field(validation_alias="total_lines") + total_size: int = Field(validation_alias=AliasChoices("total_size", "totalSize")) + total_lines: int = Field(validation_alias=AliasChoices("total_lines", "totalLines")) class _MetadataFileInfo(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods diff --git a/libs/labelbox/src/labelbox/utils.py b/libs/labelbox/src/labelbox/utils.py index ce0f3c210..30e335be2 100644 --- a/libs/labelbox/src/labelbox/utils.py +++ b/libs/labelbox/src/labelbox/utils.py @@ -6,8 +6,8 @@ from dateutil.utils import default_tzinfo from urllib.parse import urlparse -from pydantic import BaseModel -from labelbox import pydantic_compat +from pydantic import BaseModel, ConfigDict +from pydantic.alias_generators import to_camel UPPERCASE_COMPONENTS = ['uri', 'rgb'] ISO_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' @@ -62,10 +62,7 @@ def is_valid_uri(uri): class _CamelCaseMixin(BaseModel): - - class Config: - allow_population_by_field_name = True - alias_generator = camel_case + model_config = ConfigDict(arbitrary_types_allowed = True, alias_generator = to_camel) class _NoCoercionMixin: From b1604a50c3b06710b23d29d5ee62c8f24310ef63 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:35:57 -0500 Subject: [PATCH 08/34] reverted changes to pyproject --- libs/labelbox/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index 11de0eb84..35865e6f5 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -85,8 +85,8 @@ unit = "pytest tests/unit" # LABELBOX_TEST_ENVIRON="ephemeral" \ # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ -integration = { cmd = "pytest tests/integration/test_send_to_annotate.py" } -data = { cmd = "pytest tests/unit" } +integration = { cmd = "pytest tests/integration" } +data = { cmd = "pytest tests/data" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } From 524a46b375e248dbcb51ca5ba9dd00152a0114ec Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:38:11 -0500 Subject: [PATCH 09/34] changed feature_serilazier --- .../classification/classification.py | 12 ++++++------ .../src/labelbox/data/annotation_types/feature.py | 4 ++-- libs/labelbox/src/labelbox/data/mixins.py | 4 ++-- libs/labelbox/src/labelbox/pydantic_serializers.py | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py index b0bca72ae..0cda0a2ed 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py @@ -10,7 +10,7 @@ from pydantic import BaseModel, model_serializer from ..feature import FeatureSchema -from labelbox.pydantic_serializers import feature_serializer +from labelbox.pydantic_serializers import _feature_serializer class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): @@ -30,7 +30,7 @@ class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): @model_serializer(mode="wrap") def serialize_model(self, handler): - return feature_serializer(handler(self)) + return _feature_serializer(handler(self)) class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ A classification with only one selected option allowed @@ -42,7 +42,7 @@ class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - return feature_serializer(handler(self)) + return _feature_serializer(handler(self)) class Checklist(ConfidenceMixin, BaseModel): @@ -55,7 +55,7 @@ class Checklist(ConfidenceMixin, BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - return feature_serializer(handler(self)) + return _feature_serializer(handler(self)) class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel): @@ -68,7 +68,7 @@ class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): - return feature_serializer(handler(self)) + return _feature_serializer(handler(self)) class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, @@ -93,4 +93,4 @@ class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, @model_serializer(mode="wrap") def serialize_model(self, handler): - return feature_serializer(handler(self)) + return _feature_serializer(handler(self)) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/feature.py b/libs/labelbox/src/labelbox/data/annotation_types/feature.py index aa9063cf4..5b708f595 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/feature.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/feature.py @@ -1,7 +1,7 @@ from typing import Optional from pydantic import BaseModel, model_validator, model_serializer from .types import Cuid -from labelbox.pydantic_serializers import feature_serializer +from labelbox.pydantic_serializers import _feature_serializer class FeatureSchema(BaseModel): @@ -23,4 +23,4 @@ def must_set_one(self): @model_serializer(mode="wrap") def model_serializer(self, handler): res = handler(self) - return feature_serializer(res) + return _feature_serializer(res) diff --git a/libs/labelbox/src/labelbox/data/mixins.py b/libs/labelbox/src/labelbox/data/mixins.py index 0352dba7d..e95cec3f4 100644 --- a/libs/labelbox/src/labelbox/data/mixins.py +++ b/libs/labelbox/src/labelbox/data/mixins.py @@ -5,7 +5,7 @@ from labelbox.exceptions import ConfidenceNotSupportedException, CustomMetricsNotSupportedException from warnings import warn -from labelbox.pydantic_serializers import feature_serializer +from labelbox.pydantic_serializers import _feature_serializer class ConfidenceMixin(BaseModel): @@ -22,7 +22,7 @@ def confidence_valid_float(cls, value): @model_serializer(mode="wrap") def serialize_model(self, handler): res = handler(self) - res = feature_serializer(res) + res = _feature_serializer(res) return res diff --git a/libs/labelbox/src/labelbox/pydantic_serializers.py b/libs/labelbox/src/labelbox/pydantic_serializers.py index c2f2ac630..743a418ac 100644 --- a/libs/labelbox/src/labelbox/pydantic_serializers.py +++ b/libs/labelbox/src/labelbox/pydantic_serializers.py @@ -1,6 +1,6 @@ from typing import Dict -def feature_serializer(res: Dict) -> Dict: +def _feature_serializer(res: Dict) -> Dict: """Used as a with custom model serializer for pydantics. This ensures backwards compatibility since pydantic V1 allowed you to override Dict method. This method needs to be used for all base classes and sub classes. We should look at getting this removed.""" if "customMetrics" in res and res["customMetrics"] is None: res.pop("customMetrics") From e332119821078ee145ce8fdb928c1797ac8f9051 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 19:39:12 -0500 Subject: [PATCH 10/34] removed all pydantic_compat --- .../data/annotation_types/data/raster.py | 9 +- .../data/annotation_types/data/text.py | 11 +- .../data/annotation_types/data/tiled_image.py | 16 ++- .../data/annotation_types/data/video.py | 10 +- .../data/annotation_types/geometry/line.py | 5 +- .../data/annotation_types/geometry/mask.py | 4 +- .../data/annotation_types/geometry/polygon.py | 4 +- .../data/annotation_types/metrics/base.py | 17 +-- .../data/annotation_types/metrics/scalar.py | 10 +- .../annotation_types/ner/document_entity.py | 1 - .../labelbox/data/annotation_types/video.py | 1 - .../data/serialization/coco/annotation.py | 8 +- .../data/serialization/coco/categories.py | 4 +- .../serialization/coco/instance_dataset.py | 4 +- .../serialization/coco/panoptic_dataset.py | 4 +- .../labelbox/data/serialization/coco/path.py | 10 +- .../labelbox_v1/classification.py | 4 +- .../data/serialization/labelbox_v1/feature.py | 19 ++-- .../data/serialization/labelbox_v1/label.py | 39 +++---- .../data/serialization/labelbox_v1/objects.py | 37 +++---- .../data/serialization/ndjson/base.py | 10 +- .../serialization/ndjson/classification.py | 43 ++++---- .../data/serialization/ndjson/label.py | 1 - .../data/serialization/ndjson/metric.py | 15 +-- .../data/serialization/ndjson/objects.py | 7 +- .../data/serialization/ndjson/relationship.py | 4 +- libs/labelbox/src/labelbox/pydantic_compat.py | 34 ------ .../labelbox/schema/bulk_import_request.py | 100 +++++++++--------- .../src/labelbox/schema/data_row_metadata.py | 12 +-- libs/labelbox/src/labelbox/schema/dataset.py | 3 +- .../labelbox/src/labelbox/schema/embedding.py | 2 +- .../src/labelbox/schema/foundry/model.py | 6 +- .../schema/internal/data_row_uploader.py | 4 +- .../schema/internal/data_row_upsert_item.py | 1 - .../src/labelbox/schema/label_score.py | 4 +- libs/labelbox/src/labelbox/schema/ontology.py | 5 +- .../src/labelbox/schema/project_overview.py | 2 +- .../schema/send_to_annotate_params.py | 7 +- .../src/labelbox/schema/user_group.py | 8 +- libs/labelbox/src/labelbox/utils.py | 8 +- .../data/annotation_types/data/test_raster.py | 4 +- .../data/annotation_types/data/test_text.py | 4 +- .../data/annotation_types/data/test_video.py | 4 +- .../annotation_types/geometry/test_line.py | 6 +- .../annotation_types/geometry/test_mask.py | 4 +- .../annotation_types/geometry/test_point.py | 4 +- .../annotation_types/geometry/test_polygon.py | 9 +- .../geometry/test_rectangle.py | 4 +- .../data/annotation_types/test_annotation.py | 10 +- .../tests/data/annotation_types/test_label.py | 2 +- .../data/annotation_types/test_metrics.py | 18 ++-- .../data/annotation_types/test_tiled_image.py | 4 +- 52 files changed, 247 insertions(+), 319 deletions(-) delete mode 100644 libs/labelbox/src/labelbox/pydantic_compat.py diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index 498cf39a9..cf78aa0c5 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -9,7 +9,7 @@ import requests import numpy as np -from pydantic import BaseModel, model_validator +from pydantic import BaseModel, model_validator, ConfigDict from labelbox.exceptions import InternalServerError from .base_data import BaseData from ..types import TypedArray @@ -22,6 +22,7 @@ class RasterData(BaseModel, ABC): file_path: Optional[str] = None url: Optional[str] = None arr: Optional[TypedArray[Literal['uint8']]] = None + model_config = ConfigDict(extra="forbid", copy_on_model_validation="none") @classmethod def from_2D_arr(cls, arr: Union[TypedArray[Literal['uint8']], @@ -185,12 +186,6 @@ def __repr__(self) -> str: f"url={self.url}," \ f"arr={symbol_or_none(self.arr)})" - class Config: - # Required for sharing references - copy_on_model_validation = 'none' - # Required for discriminating between data types - extra = 'forbid' - class MaskData(RasterData): """Used to represent a segmentation Mask diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py index e46eee507..9334524b3 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py @@ -4,7 +4,7 @@ from requests.exceptions import ConnectTimeout from google.api_core import retry -from labelbox import pydantic_compat +from pydantic import ConfigDict, model_validator from labelbox.exceptions import InternalServerError from labelbox.typing_imports import Literal from labelbox.utils import _NoCoercionMixin @@ -26,6 +26,7 @@ class TextData(BaseData, _NoCoercionMixin): file_path: Optional[str] = None text: Optional[str] = None url: Optional[str] = None + model_config = ConfigDict(extra="forbid") @property def value(self) -> str: @@ -64,7 +65,7 @@ def fetch_remote(self) -> str: """ response = requests.get(self.url) if response.status_code in [500, 502, 503, 504]: - raise labelbox.exceptions.InternalServerError(response.text) + raise InternalServerError(response.text) response.raise_for_status() return response.text @@ -90,7 +91,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> None: "One of url, im_bytes, file_path, numpy must not be None.") return self.url - @pydantic_compat.root_validator + @model_validator(mode="after") def validate_date(cls, values): file_path = values.get("file_path") text = values.get("text") @@ -107,7 +108,3 @@ def __repr__(self) -> str: return f"TextData(file_path={self.file_path}," \ f"text={self.text[:30] + '...' if self.text is not None else None}," \ f"url={self.url})" - - class config: - # Required for discriminating between data types - extra = 'forbid' diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py index fae0d426a..b370dfe29 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py @@ -12,12 +12,11 @@ from PIL import Image from pyproj import Transformer from pygeotile.point import Point as PygeoPoint -from labelbox import pydantic_compat from labelbox.data.annotation_types import Rectangle, Point, Line, Polygon from .base_data import BaseData from .raster import RasterData -from pydantic import BaseModel, field_validator, model_validator +from pydantic import BaseModel, field_validator, model_validator, ConfigDict VALID_LAT_RANGE = range(-90, 90) VALID_LNG_RANGE = range(-180, 180) @@ -83,7 +82,7 @@ def validate_bounds_lat_lng(cls, values): return values -class TileLayer(pydantic_compat.BaseModel): +class TileLayer(BaseModel): """ Url that contains the tile layer. Must be in the format: https://c.tile.openstreetmap.org/{z}/{x}/{y}.png @@ -99,7 +98,7 @@ class TileLayer(pydantic_compat.BaseModel): def asdict(self) -> Dict[str, str]: return {"tileLayerUrl": self.url, "name": self.name} - @pydantic_compat.validator('url') + @field_validator('url') def validate_url(cls, url): xyz_format = "/{z}/{x}/{y}" if xyz_format not in url: @@ -344,7 +343,7 @@ def _validate_num_tiles(self, xstart: float, ystart: float, xend: float, f"Max allowed tiles are {max_tiles}" f"Increase max tiles or reduce zoom level.") - @pydantic_compat.validator('zoom_levels') + @field_validator('zoom_levels') def validate_zoom_levels(cls, zoom_levels): if zoom_levels[0] > zoom_levels[1]: raise ValueError( @@ -353,15 +352,12 @@ def validate_zoom_levels(cls, zoom_levels): return zoom_levels -class EPSGTransformer(pydantic_compat.BaseModel): +class EPSGTransformer(BaseModel): """Transformer class between different EPSG's. Useful when wanting to project in different formats. """ - - class Config: - arbitrary_types_allowed = True - transformer: Any + model_config = ConfigDict(arbitrary_types_allowed = True) @staticmethod def _is_simple(epsg: EPSG) -> bool: diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py index 3ebda5c4c..2a26bf1ff 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py @@ -12,7 +12,7 @@ from .base_data import BaseData from ..types import TypedArray -from labelbox import pydantic_compat +from pydantic import ConfigDict, model_validator logger = logging.getLogger(__name__) @@ -24,6 +24,8 @@ class VideoData(BaseData): file_path: Optional[str] = None url: Optional[str] = None frames: Optional[Dict[int, TypedArray[Literal['uint8']]]] = None + # Required for discriminating between data types + model_config = ConfigDict(extra = "forbid") def load_frames(self, overwrite: bool = False) -> None: """ @@ -148,7 +150,7 @@ def frames_to_video(self, out.release() return file_path - @pydantic_compat.root_validator + @model_validator(mode="after") def validate_data(cls, values): file_path = values.get("file_path") url = values.get("url") @@ -166,7 +168,3 @@ def __repr__(self) -> str: return f"VideoData(file_path={self.file_path}," \ f"frames={'...' if self.frames is not None else None}," \ f"url={self.url})" - - class Config: - # Required for discriminating between data types - extra = 'forbid' diff --git a/libs/labelbox/src/labelbox/data/annotation_types/geometry/line.py b/libs/labelbox/src/labelbox/data/annotation_types/geometry/line.py index 0ae0c3b1d..fcd31b4e7 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/geometry/line.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/geometry/line.py @@ -9,8 +9,7 @@ from .point import Point from .geometry import Geometry -from labelbox import pydantic_compat - +from pydantic import field_validator class Line(Geometry): """Line annotation @@ -65,7 +64,7 @@ def draw(self, color=color, thickness=thickness) - @pydantic_compat.validator('points') + @field_validator('points') def is_geom_valid(cls, points): if len(points) < 2: raise ValueError( diff --git a/libs/labelbox/src/labelbox/data/annotation_types/geometry/mask.py b/libs/labelbox/src/labelbox/data/annotation_types/geometry/mask.py index 7c903b644..39051182f 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/geometry/mask.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/geometry/mask.py @@ -8,7 +8,7 @@ from ..data import MaskData from .geometry import Geometry -from labelbox import pydantic_compat +from pydantic import field_validator class Mask(Geometry): @@ -122,7 +122,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> str: """ return self.mask.create_url(signer) - @pydantic_compat.validator('color') + @field_validator('color') def is_valid_color(cls, color): if isinstance(color, (tuple, list)): if len(color) == 1: diff --git a/libs/labelbox/src/labelbox/data/annotation_types/geometry/polygon.py b/libs/labelbox/src/labelbox/data/annotation_types/geometry/polygon.py index 423861e31..96e1f0c94 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/geometry/polygon.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/geometry/polygon.py @@ -9,7 +9,7 @@ from .geometry import Geometry from .point import Point -from labelbox import pydantic_compat +from pydantic import field_validator class Polygon(Geometry): @@ -68,7 +68,7 @@ def draw(self, return cv2.fillPoly(canvas, pts, color) return cv2.polylines(canvas, pts, True, color, thickness) - @pydantic_compat.validator('points') + @field_validator('points') def is_geom_valid(cls, points): if len(points) < 3: raise ValueError( diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py index ec2ee0581..e27284853 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py @@ -1,8 +1,7 @@ from abc import ABC from typing import Dict, Optional, Any, Union -from labelbox import pydantic_compat -from pydantic import confloat +from pydantic import confloat, BaseModel, model_serializer, field_validator, ValidationError, error_wrappers ConfidenceValue = confloat(ge=0, le=1) @@ -10,23 +9,25 @@ MAX_CONFIDENCE_SCORES = 15 -class BaseMetric(pydantic_compat.BaseModel, ABC): +class BaseMetric(BaseModel, ABC): value: Union[Any, Dict[float, Any]] feature_name: Optional[str] = None subclass_name: Optional[str] = None extra: Dict[str, Any] = {} - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) return {k: v for k, v in res.items() if v is not None} - @pydantic_compat.validator('value') + + @field_validator('value') def validate_value(cls, value): if isinstance(value, Dict): if not (MIN_CONFIDENCE_SCORES <= len(value) <= MAX_CONFIDENCE_SCORES): - raise pydantic_compat.ValidationError([ - pydantic_compat.ErrorWrapper(ValueError( + raise ValidationError([ + error_wrappers(ValueError( "Number of confidence scores must be greater" f" than or equal to {MIN_CONFIDENCE_SCORES} and" f" less than or equal to {MAX_CONFIDENCE_SCORES}. Found {len(value)}" diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 2b814a3d9..b82ecefcd 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -3,8 +3,7 @@ from .base import ConfidenceValue, BaseMetric -from labelbox import pydantic_compat -from pydantic import confloat +from pydantic import confloat, field_validator, model_serializer ScalarMetricValue = confloat(ge=0, le=100_000_000) ScalarMetricConfidenceValue = Dict[ConfidenceValue, ScalarMetricValue] @@ -34,7 +33,7 @@ class ScalarMetric(BaseMetric): value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN - @pydantic_compat.validator('metric_name') + @field_validator.validator('metric_name') def validate_metric_name(cls, name: Union[str, None]): if name is None: return None @@ -44,8 +43,9 @@ def validate_metric_name(cls, name: Union[str, None]): "Please provide another value for `metric_name`.") return name - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def dict(self, handler): + res = handler(self) if res.get('metric_name') is None: res.pop('aggregation') return res diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py index 15b1b015a..c2acecd7c 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/document_entity.py @@ -1,6 +1,5 @@ from typing import List -from labelbox import pydantic_compat from labelbox.utils import _CamelCaseMixin from pydantic import BaseModel, field_validator diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index a936a1d2f..776a998c9 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -1,7 +1,6 @@ from enum import Enum from typing import List, Optional, Tuple -from labelbox import pydantic_compat from labelbox.data.annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation from labelbox.data.annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py b/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py index 64742c8e2..32668eaec 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py @@ -10,10 +10,10 @@ from ...annotation_types.annotation import ObjectAnnotation from ...annotation_types.classification.classification import ClassificationAnnotation -from .... import pydantic_compat import numpy as np from .path import PathSerializerMixin +from pydantic import BaseModel def rle_decoding(rle_arr: List[int], w: int, h: int) -> np.ndarray: @@ -40,7 +40,7 @@ def get_annotation_lookup(annotations): return annotation_lookup -class SegmentInfo(pydantic_compat.BaseModel): +class SegmentInfo(BaseModel): id: int category_id: int area: int @@ -48,12 +48,12 @@ class SegmentInfo(pydantic_compat.BaseModel): iscrowd: int = 0 -class RLE(pydantic_compat.BaseModel): +class RLE(BaseModel): counts: List[int] size: Tuple[int, int] # h,w or w,h? -class COCOObjectAnnotation(pydantic_compat.BaseModel): +class COCOObjectAnnotation(BaseModel): # All segmentations for a particular class in an image... # So each image will have one of these for each class present in the image.. # Annotations only exist if there is data.. diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/categories.py b/libs/labelbox/src/labelbox/data/serialization/coco/categories.py index 167737c67..07ecacb03 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/categories.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/categories.py @@ -1,10 +1,10 @@ import sys from hashlib import md5 -from .... import pydantic_compat +from pydantic import BaseModel -class Categories(pydantic_compat.BaseModel): +class Categories(BaseModel): id: int name: str supercategory: str diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/instance_dataset.py b/libs/labelbox/src/labelbox/data/serialization/coco/instance_dataset.py index 9a6b122f3..7cade81a1 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/instance_dataset.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/instance_dataset.py @@ -6,13 +6,13 @@ import numpy as np from tqdm import tqdm -from .... import pydantic_compat from ...annotation_types import ImageData, MaskData, Mask, ObjectAnnotation, Label, Polygon, Point, Rectangle from ...annotation_types.collection import LabelCollection from .categories import Categories, hash_category_name from .annotation import COCOObjectAnnotation, RLE, get_annotation_lookup, rle_decoding from .image import CocoImage, get_image, get_image_id +from pydantic import BaseModel def mask_to_coco_object_annotation( @@ -129,7 +129,7 @@ def process_label( return image, coco_annotations, categories -class CocoInstanceDataset(pydantic_compat.BaseModel): +class CocoInstanceDataset(BaseModel): info: Dict[str, Any] = {} images: List[CocoImage] annotations: List[COCOObjectAnnotation] diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/panoptic_dataset.py b/libs/labelbox/src/labelbox/data/serialization/coco/panoptic_dataset.py index b6d2c9ae6..4d6b9e2ef 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/panoptic_dataset.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/panoptic_dataset.py @@ -2,7 +2,6 @@ from typing import Dict, Any, List, Union from pathlib import Path -from labelbox import pydantic_compat from tqdm import tqdm import numpy as np from PIL import Image @@ -16,6 +15,7 @@ from .categories import Categories, hash_category_name from .image import CocoImage, get_image, get_image_id, id_to_rgb from .annotation import PanopticAnnotation, SegmentInfo, get_annotation_lookup +from pydantic import BaseModel def vector_to_coco_segment_info(canvas: np.ndarray, @@ -115,7 +115,7 @@ def process_label(label: Label, segments_info=segments), categories, is_thing -class CocoPanopticDataset(pydantic_compat.BaseModel): +class CocoPanopticDataset(BaseModel): info: Dict[str, Any] = {} images: List[CocoImage] annotations: List[PanopticAnnotation] diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/path.py b/libs/labelbox/src/labelbox/data/serialization/coco/path.py index 6f523152c..8f6786655 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/path.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/path.py @@ -1,9 +1,9 @@ -from labelbox import pydantic_compat from pathlib import Path +from pydantic import BaseModel, model_serializer +class PathSerializerMixin(BaseModel): -class PathSerializerMixin(pydantic_compat.BaseModel): - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) return {k: str(v) if isinstance(v, Path) else v for k, v in res.items()} diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py index 8600f08e3..06b9c6200 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py @@ -1,11 +1,11 @@ from typing import List, Union -from labelbox import pydantic_compat from .feature import LBV1Feature from ...annotation_types.annotation import ClassificationAnnotation from ...annotation_types.classification import Checklist, ClassificationAnswer, Radio, Text, Dropdown from ...annotation_types.types import Cuid +from pydantic import BaseModel class LBV1ClassificationAnswer(LBV1Feature): @@ -90,7 +90,7 @@ def from_common(cls, text: Text, feature_schema_id: Cuid, return cls(schema_id=feature_schema_id, answer=text.answer, **extra) -class LBV1Classifications(pydantic_compat.BaseModel): +class LBV1Classifications(BaseModel): classifications: List[Union[LBV1Text, LBV1Radio, LBV1Dropdown, LBV1Checklist]] = [] diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py index cefddd079..54d6b6459 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py @@ -1,31 +1,28 @@ from typing import Optional -from labelbox import pydantic_compat - -from labelbox.utils import camel_case from ...annotation_types.types import Cuid +from pydantic import BaseModel, ConfigDict, model_validator, model_serializer +from pydantic.alias_generators import to_camel -class LBV1Feature(pydantic_compat.BaseModel): +class LBV1Feature(BaseModel): keyframe: Optional[bool] = None title: str = None value: Optional[str] = None schema_id: Optional[Cuid] = None feature_id: Optional[Cuid] = None + model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) - @pydantic_compat.root_validator + @model_validator(mode = "after") def check_ids(cls, values): if values.get('value') is None: values['value'] = values['title'] return values - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode = "wrap") + def serialize_model(self, handler): + res = handler(self) # This means these are no video frames .. if self.keyframe is None: res.pop('keyframe') return res - - class Config: - allow_population_by_field_name = True - alias_generator = camel_case diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py index ee45bc8f0..b150db71a 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py @@ -2,8 +2,6 @@ from labelbox.utils import camel_case from typing import List, Optional, Union, Dict, Any -from labelbox import pydantic_compat - from ...annotation_types.annotation import (ClassificationAnnotation, ObjectAnnotation) from ...annotation_types.video import VideoClassificationAnnotation, VideoObjectAnnotation @@ -11,6 +9,8 @@ from ...annotation_types.label import Label from .classification import LBV1Classifications from .objects import LBV1Objects, LBV1TextEntity +from pydantic import Field, BaseModel, ConfigDict +from pydantic.alias_generators import to_camel class LBV1LabelAnnotations(LBV1Classifications, LBV1Objects): @@ -35,7 +35,8 @@ def from_common( class LBV1LabelAnnotationsVideo(LBV1LabelAnnotations): - frame_number: int = pydantic_compat.Field(..., alias='frameNumber') + frame_number: int = Field(..., alias='frameNumber') + model_config = ConfigDict(populate_by_name = True) def to_common( self @@ -100,36 +101,30 @@ def from_common( return result - class Config: - allow_population_by_field_name = True - -class Review(pydantic_compat.BaseModel): +class Review(BaseModel): score: int id: str created_at: str created_by: str label_id: Optional[str] = None + model_config = ConfigDict(alias_generator = to_camel) - class Config: - alias_generator = camel_case +Extra = lambda name: Field(None, alias=name, extra_field=True) -Extra = lambda name: pydantic_compat.Field(None, alias=name, extra_field=True) - -class LBV1Label(pydantic_compat.BaseModel): +class LBV1Label(BaseModel): label: Union[LBV1LabelAnnotations, - List[LBV1LabelAnnotationsVideo]] = pydantic_compat.Field( + List[LBV1LabelAnnotationsVideo]] = Field( ..., alias='Label') - data_row_id: str = pydantic_compat.Field(..., alias="DataRow ID") - row_data: str = pydantic_compat.Field(None, alias="Labeled Data") - id: Optional[str] = pydantic_compat.Field(None, alias='ID') - external_id: Optional[str] = pydantic_compat.Field(None, - alias="External ID") - data_row_media_attributes: Optional[Dict[str, Any]] = pydantic_compat.Field( + data_row_id: str = Field(..., alias="DataRow ID") + row_data: str = Field(None, alias="Labeled Data") + id: Optional[str] = Field(None, alias='ID') + external_id: Optional[str] = Field(None, alias="External ID") + data_row_media_attributes: Optional[Dict[str, Any]] = Field( {}, alias="Media Attributes") - data_row_metadata: Optional[List[Dict[str, Any]]] = pydantic_compat.Field( + data_row_metadata: Optional[List[Dict[str, Any]]] = Field( [], alias="DataRow Metadata") created_by: Optional[str] = Extra('Created By') @@ -148,6 +143,7 @@ class LBV1Label(pydantic_compat.BaseModel): media_type: Optional[str] = Extra('media_type') data_split: Optional[str] = Extra('Data Split') global_key: Optional[str] = Extra('Global Key') + model_config = ConfigDict(populate_by_name = True) def to_common(self) -> Label: if isinstance(self.label, list): @@ -246,6 +242,3 @@ def _is_url(self) -> bool: return self.row_data.startswith( ("http://", "https://", "gs://", "s3://")) or "tileLayerUrl" in self.row_data - - class Config: - allow_population_by_field_name = True diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py index 19f6c0717..08b4ed2ee 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py @@ -4,7 +4,6 @@ except: from typing_extensions import Literal -from labelbox import pydantic_compat import numpy as np from .classification import LBV1Checklist, LBV1Classifications, LBV1Radio, LBV1Text, LBV1Dropdown @@ -15,6 +14,7 @@ from ...annotation_types.geometry import Line, Mask, Point, Polygon, Rectangle from ...annotation_types.ner import TextEntity from ...annotation_types.types import Cuid +from pydantic import BaseModel, Field, model_serializer, field_serializer class LBV1ObjectBase(LBV1Feature): @@ -25,15 +25,16 @@ class LBV1ObjectBase(LBV1Feature): page: Optional[int] = None unit: Optional[str] = None - def dict(self, *args, **kwargs) -> Dict[str, Any]: - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) # This means these are not video frames .. if self.instanceURI is None: res.pop('instanceURI') return res - @pydantic_compat.validator('classifications', pre=True) - def validate_subclasses(cls, value, field): + @field_serializer('classifications', mode="before") + def validate_subclasses(cls, value): # checklist subclasses create extra unessesary nesting. So we just remove it. if isinstance(value, list) and len(value): subclasses = [] @@ -49,24 +50,24 @@ def validate_subclasses(cls, value, field): return value -class TIPointCoordinate(pydantic_compat.BaseModel): +class TIPointCoordinate(BaseModel): coordinates: List[float] -class TILineCoordinate(pydantic_compat.BaseModel): +class TILineCoordinate(BaseModel): coordinates: List[List[float]] -class TIPolygonCoordinate(pydantic_compat.BaseModel): +class TIPolygonCoordinate(BaseModel): coordinates: List[List[List[float]]] -class TIRectangleCoordinate(pydantic_compat.BaseModel): +class TIRectangleCoordinate(BaseModel): coordinates: List[List[List[float]]] class LBV1TIPoint(LBV1ObjectBase): - object_type: Literal['point'] = pydantic_compat.Field(..., alias='type') + object_type: Literal['point'] = Field(..., alias='type') geometry: TIPointCoordinate def to_common(self) -> Point: @@ -75,7 +76,7 @@ def to_common(self) -> Point: class LBV1TILine(LBV1ObjectBase): - object_type: Literal['polyline'] = pydantic_compat.Field(..., alias='type') + object_type: Literal['polyline'] = Field(..., alias='type') geometry: TILineCoordinate def to_common(self) -> Line: @@ -85,7 +86,7 @@ def to_common(self) -> Line: class LBV1TIPolygon(LBV1ObjectBase): - object_type: Literal['polygon'] = pydantic_compat.Field(..., alias='type') + object_type: Literal['polygon'] = Field(..., alias='type') geometry: TIPolygonCoordinate def to_common(self) -> Polygon: @@ -95,7 +96,7 @@ def to_common(self) -> Polygon: class LBV1TIRectangle(LBV1ObjectBase): - object_type: Literal['rectangle'] = pydantic_compat.Field(..., alias='type') + object_type: Literal['rectangle'] = Field(..., alias='type') geometry: TIRectangleCoordinate def to_common(self) -> Rectangle: @@ -111,12 +112,12 @@ def to_common(self) -> Rectangle: end=Point(x=end[0], y=end[1])) -class _Point(pydantic_compat.BaseModel): +class _Point(BaseModel): x: float y: float -class _Box(pydantic_compat.BaseModel): +class _Box(BaseModel): top: float left: float height: float @@ -230,12 +231,12 @@ def from_common(cls, mask: Mask, }) -class _TextPoint(pydantic_compat.BaseModel): +class _TextPoint(BaseModel): start: int end: int -class _Location(pydantic_compat.BaseModel): +class _Location(BaseModel): location: _TextPoint @@ -263,7 +264,7 @@ def from_common(cls, text_entity: TextEntity, **extra) -class LBV1Objects(pydantic_compat.BaseModel): +class LBV1Objects(BaseModel): objects: List[Union[ LBV1Line, LBV1Point, diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index f6773a9ce..7fb5beee4 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -2,9 +2,8 @@ from uuid import uuid4 from labelbox.utils import _CamelCaseMixin, is_exactly_one_set -from labelbox import pydantic_compat from ...annotation_types.types import Cuid -from pydantic import field_validator, model_validator +from pydantic import field_validator, model_validator, model_serializer class DataRow(_CamelCaseMixin): @@ -43,15 +42,16 @@ class NDAnnotation(NDJsonBase): page: Optional[int] = None unit: Optional[str] = None - @pydantic_compat.root_validator() + @model_validator(mode="after") def must_set_one(cls, values): if ('schema_id' not in values or values['schema_id'] is None) and ('name' not in values or values['name'] is None): raise ValueError("Schema id or name are not set. Set either one.") return values - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) if 'name' in res and res['name'] is None: res.pop('name') if 'schemaId' in res and res['schemaId'] is None: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index edd8c7343..2ed1a2f3c 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -1,23 +1,23 @@ from typing import Any, Dict, List, Union, Optional -from labelbox import pydantic_compat from labelbox.data.mixins import ConfidenceMixin, CustomMetric, CustomMetricsMixin from labelbox.data.serialization.ndjson.base import DataRow, NDAnnotation -from labelbox.utils import camel_case from ...annotation_types.annotation import ClassificationAnnotation from ...annotation_types.video import VideoClassificationAnnotation from ...annotation_types.llm_prompt_response.prompt import PromptClassificationAnnotation, PromptText from ...annotation_types.classification.classification import ClassificationAnswer, Dropdown, Text, Checklist, Radio from ...annotation_types.types import Cuid from ...annotation_types.data import TextData, VideoData, ImageData -from pydantic import model_validator, Field, BaseModel +from pydantic import model_validator, Field, BaseModel, ConfigDict, model_serializer +from pydantic.alias_generators import to_camel class NDAnswer(ConfidenceMixin, CustomMetricsMixin): name: Optional[str] = None schema_id: Optional[Cuid] = None classifications: Optional[List['NDSubclassificationType']] = [] + model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) @model_validator(mode="after") def must_set_one(cls, values): @@ -26,8 +26,9 @@ def must_set_one(cls, values): raise ValueError("Schema id or name are not set. Set either one.") return values - def dict(self, *args, **kwargs): - res = super().model_dump(*args, **kwargs) + @model_serializer(mode = "wrap") + def serialize_model(self, handler): + res = handler(self) if 'name' in res and res['name'] is None: res.pop('name') if 'schemaId' in res and res['schemaId'] is None: @@ -36,14 +37,10 @@ def dict(self, *args, **kwargs): res.pop('classifications') else: res['classifications'] = [ - c.dict(*args, **kwargs) for c in self.classifications + c.model_dump() for c in self.classifications ] return res - class Config: - allow_population_by_field_name = True - alias_generator = camel_case - class FrameLocation(BaseModel): end: int @@ -54,8 +51,9 @@ class VideoSupported(BaseModel): # Note that frames are only allowed as top level inferences for video frames: Optional[List[FrameLocation]] = None - def dict(self, *args, **kwargs): - res = super().model_dump(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) # This means these are no video frames .. if self.frames is None: res.pop('frames') @@ -116,8 +114,9 @@ def from_common(cls, checklist: Checklist, name: str, name=name, schema_id=feature_schema_id) - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def dict(self, handler): + res = handler(self) if 'answers' in res: res['answer'] = res.pop('answers') return res @@ -410,14 +409,14 @@ def from_common( NDSubclassificationType = Union[NDChecklistSubclass, NDRadioSubclass, NDTextSubclass] -NDAnswer.update_forward_refs() -NDChecklistSubclass.update_forward_refs() -NDChecklist.update_forward_refs() -NDRadioSubclass.update_forward_refs() -NDRadio.update_forward_refs() -NDText.update_forward_refs() -NDPromptText.update_forward_refs() -NDTextSubclass.update_forward_refs() +NDAnswer.model_rebuild() +NDChecklistSubclass.model_rebuild() +NDChecklist.model_rebuild() +NDRadioSubclass.model_rebuild() +NDRadio.model_rebuild() +NDText.model_rebuild() +NDPromptText.model_rebuild() +NDTextSubclass.model_rebuild() # Make sure to keep NDChecklist prior to NDRadio in the list, # otherwise list of answers gets parsed by NDRadio whereas NDChecklist must be used diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index bb487be25..a9e94ba44 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -4,7 +4,6 @@ from collections import defaultdict import warnings -from labelbox import pydantic_compat from ...annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation from ...annotation_types.relationship import RelationshipAnnotation diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py index b918604b5..45a7ded14 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py @@ -8,18 +8,18 @@ from labelbox.data.annotation_types.metrics.confusion_matrix import ( ConfusionMatrixAggregation, ConfusionMatrixMetric, ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue) +from pydantic import ConfigDict, model_serializer class BaseNDMetric(NDJsonBase): metric_value: float feature_name: Optional[str] = None subclass_name: Optional[str] = None + model_config = ConfigDict(use_enum_values = True) - class Config: - use_enum_values = True - - def dict(self, *args, **kwargs): - res = super().model_dump(*args, **kwargs) + @model_serializer(mode = "wrap") + def serialize_model(self, handler): + res = handler(self) for field in ['featureName', 'subclassName']: if res[field] is None: res.pop(field) @@ -77,8 +77,9 @@ def from_common(cls, metric: ScalarMetric, aggregation=metric.aggregation.value, data_row=DataRow(id=data.uid, global_key=data.global_key)) - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode = "wrap") + def serialize_model(self, handler): + res = handler(self) # For backwards compatibility. if res['metricName'] is None: res.pop('metricName') diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index eb7fa73f4..d07499f99 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -7,7 +7,6 @@ from labelbox.data.mixins import ConfidenceMixin, CustomMetricsMixin, CustomMetric, CustomMetricsNotSupportedMixin import numpy as np -from labelbox import pydantic_compat from PIL import Image from labelbox.data.annotation_types import feature @@ -455,12 +454,12 @@ def from_common(cls, segments: List[DICOMObjectAnnotation], data: VideoData, group_key=group_key) -class _URIMask(pydantic_compat.BaseModel): +class _URIMask(BaseModel): instanceURI: str colorRGB: Tuple[int, int, int] -class _PNGMask(pydantic_compat.BaseModel): +class _PNGMask(BaseModel): png: str @@ -565,7 +564,7 @@ def from_common(cls, annotation, data): ) -class Location(pydantic_compat.BaseModel): +class Location(BaseModel): start: int end: int diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py index 82976aedb..d95c1584f 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py @@ -1,5 +1,5 @@ from typing import Union -from labelbox import pydantic_compat +from pydantic import BaseModel from .base import NDAnnotation, DataRow from ...annotation_types.data import ImageData, TextData from ...annotation_types.relationship import RelationshipAnnotation @@ -10,7 +10,7 @@ SUPPORTED_ANNOTATIONS = NDObjectType -class _Relationship(pydantic_compat.BaseModel): +class _Relationship(BaseModel): source: str target: str type: str diff --git a/libs/labelbox/src/labelbox/pydantic_compat.py b/libs/labelbox/src/labelbox/pydantic_compat.py deleted file mode 100644 index 51c082480..000000000 --- a/libs/labelbox/src/labelbox/pydantic_compat.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Optional - - -def pydantic_import(class_name, sub_module_path: Optional[str] = None): - import importlib - import importlib.metadata - - # Get the version of pydantic - pydantic_version = importlib.metadata.version("pydantic") - - # Determine the module name based on the version - module_name = "pydantic" if pydantic_version.startswith( - "1") else "pydantic.v1" - module_name = f"{module_name}.{sub_module_path}" if sub_module_path else module_name - - # Import the class from the module - klass = getattr(importlib.import_module(module_name), class_name) - - return klass - - -BaseModel = pydantic_import("BaseModel") -PrivateAttr = pydantic_import("PrivateAttr") -Field = pydantic_import("Field") -ModelField = pydantic_import("ModelField", "fields") -ValidationError = pydantic_import("ValidationError") -ErrorWrapper = pydantic_import("ErrorWrapper", "error_wrappers") - -validator = pydantic_import("validator") -root_validator = pydantic_import("root_validator") -conint = pydantic_import("conint") -conlist = pydantic_import("conlist") -constr = pydantic_import("constr") -confloat = pydantic_import("confloat") diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index 9c282879e..d744ee528 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -8,7 +8,7 @@ from google.api_core import retry from labelbox import parser import requests -from labelbox import pydantic_compat +from pydantic import ValidationError, BaseModel, Field, field_validator, model_validator, ConfigDict from typing_extensions import Literal from typing import (Any, List, Optional, BinaryIO, Dict, Iterable, Tuple, Union, Type, Set, TYPE_CHECKING) @@ -29,6 +29,14 @@ NDJSON_MIME_TYPE = "application/x-ndjson" logger = logging.getLogger(__name__) +#TODO: Deprecate this library in place of labelimport and malprediction import library. + +def _determinants(parent_cls: Any) -> List[str]: + return [ + k for k, v in parent_cls.model_fields.items() + if 'determinant' in v.field_info.extra + ] + def _make_file_name(project_id: str, name: str) -> str: return f"{project_id}__{name}.ndjson" @@ -431,7 +439,7 @@ def _validate_ndjson(lines: Iterable[Dict[str, Any]], f'{uuid} already used in this import job, ' 'must be unique for the project.') uids.add(uuid) - except (pydantic_compat.ValidationError, ValueError, TypeError, + except (ValidationError, ValueError, TypeError, KeyError) as e: raise lb_exceptions.MALValidationError( f"Invalid NDJson on line {idx}") from e @@ -505,33 +513,32 @@ def get_mal_schemas(ontology): return valid_feature_schemas_by_schema_id, valid_feature_schemas_by_name -LabelboxID: str = pydantic_compat.Field(..., min_length=25, max_length=25) +LabelboxID: str = Field(..., min_length=25, max_length=25) -class Bbox(pydantic_compat.BaseModel): +class Bbox(BaseModel): top: float left: float height: float width: float -class Point(pydantic_compat.BaseModel): +class Point(BaseModel): x: float y: float -class FrameLocation(pydantic_compat.BaseModel): +class FrameLocation(BaseModel): end: int start: int -class VideoSupported(pydantic_compat.BaseModel): +class VideoSupported(BaseModel): #Note that frames are only allowed as top level inferences for video frames: Optional[List[FrameLocation]] -#Base class for a special kind of union. -# Compatible with pydantic_compat. Improves error messages over a traditional union +# Base class for a special kind of union. class SpecialUnion: def __new__(cls, **kwargs): @@ -558,25 +565,25 @@ def get_union_types(cls): @classmethod def build(cls: Any, data: Union[dict, - pydantic_compat.BaseModel]) -> "NDBase": + BaseModel]) -> "NDBase": """ Checks through all objects in the union to see which matches the input data. Args: - data (Union[dict, pydantic_compat.BaseModel]) : The data for constructing one of the objects in the union + data (Union[dict, BaseModel]) : The data for constructing one of the objects in the union raises: KeyError: data does not contain the determinant fields for any of the types supported by this SpecialUnion - pydantic_compat.ValidationError: Error while trying to construct a specific object in the union + ValidationError: Error while trying to construct a specific object in the union """ - if isinstance(data, pydantic_compat.BaseModel): - data = data.dict() + if isinstance(data, BaseModel): + data = data.model_dump() top_level_fields = [] max_match = 0 matched = None for type_ in cls.get_union_types(): - determinate_fields = type_.Config.determinants(type_) + determinate_fields = _determinants(type_) top_level_fields.append(determinate_fields) matches = sum([val in determinate_fields for val in data]) if matches == len(determinate_fields) and matches > max_match: @@ -610,15 +617,15 @@ def schema(cls): return results -class DataRow(pydantic_compat.BaseModel): +class DataRow(BaseModel): id: str -class NDFeatureSchema(pydantic_compat.BaseModel): +class NDFeatureSchema(BaseModel): schemaId: Optional[str] = None name: Optional[str] = None - @pydantic_compat.root_validator + @model_validator(mode="after") def must_set_one(cls, values): if values['schemaId'] is None and values['name'] is None: raise ValueError( @@ -630,6 +637,7 @@ class NDBase(NDFeatureSchema): ontology_type: str uuid: UUID dataRow: DataRow + model_config = ConfigDict(extra="forbid") def validate_feature_schemas(self, valid_feature_schemas_by_id, valid_feature_schemas_by_name): @@ -662,33 +670,21 @@ def validate_instance(self, valid_feature_schemas_by_id, self.validate_feature_schemas(valid_feature_schemas_by_id, valid_feature_schemas_by_name) - class Config: - #Users shouldn't to add extra data to the payload - extra = 'forbid' - - @staticmethod - def determinants(parent_cls) -> List[str]: - #This is a hack for better error messages - return [ - k for k, v in parent_cls.__fields__.items() - if 'determinant' in v.field_info.extra - ] - ###### Classifications ###### class NDText(NDBase): ontology_type: Literal["text"] = "text" - answer: str = pydantic_compat.Field(determinant=True) + answer: str = Field(json_schema_extra={"determinant": True}) #No feature schema to check class NDChecklist(VideoSupported, NDBase): ontology_type: Literal["checklist"] = "checklist" - answers: List[NDFeatureSchema] = pydantic_compat.Field(determinant=True) + answers: List[NDFeatureSchema] = Field(json_schema_extra={"determinant": True}) - @pydantic_compat.validator('answers', pre=True) + @field_validator('answers', mode="before") def validate_answers(cls, value, field): #constr not working with mypy. if not len(value): @@ -719,7 +715,7 @@ def validate_feature_schemas(self, valid_feature_schemas_by_id, class NDRadio(VideoSupported, NDBase): ontology_type: Literal["radio"] = "radio" - answer: NDFeatureSchema = pydantic_compat.Field(determinant=True) + answer: NDFeatureSchema = Field(json_schema_extra={"determinant": True}) def validate_feature_schemas(self, valid_feature_schemas_by_id, valid_feature_schemas_by_name): @@ -765,7 +761,7 @@ def validate_feature_schemas(self, valid_feature_schemas_by_id, if self.name else valid_feature_schemas_by_id[ self.schemaId]['classificationsByName']) - @pydantic_compat.validator('classifications', pre=True) + @field_validator('classifications', mode="before") def validate_subclasses(cls, value, field): #Create uuid and datarow id so we don't have to define classification objects twice #This is caused by the fact that we require these ids for top level classifications but not for subclasses @@ -783,9 +779,9 @@ def validate_subclasses(cls, value, field): class NDPolygon(NDBaseTool): ontology_type: Literal["polygon"] = "polygon" - polygon: List[Point] = pydantic_compat.Field(determinant=True) + polygon: List[Point] = Field(json_schema_extra={"determinant": True}) - @pydantic_compat.validator('polygon') + @field_validator('polygon') def is_geom_valid(cls, v): if len(v) < 3: raise ValueError( @@ -795,9 +791,9 @@ def is_geom_valid(cls, v): class NDPolyline(NDBaseTool): ontology_type: Literal["line"] = "line" - line: List[Point] = pydantic_compat.Field(determinant=True) + line: List[Point] = Field(json_schema_extra={"determinant": True}) - @pydantic_compat.validator('line') + @field_validator('line') def is_geom_valid(cls, v): if len(v) < 2: raise ValueError( @@ -807,28 +803,28 @@ def is_geom_valid(cls, v): class NDRectangle(NDBaseTool): ontology_type: Literal["rectangle"] = "rectangle" - bbox: Bbox = pydantic_compat.Field(determinant=True) + bbox: Bbox = Field(json_schema_extra={"determinant": True}) #Could check if points are positive class NDPoint(NDBaseTool): ontology_type: Literal["point"] = "point" - point: Point = pydantic_compat.Field(determinant=True) + point: Point = Field(json_schema_extra={"determinant": True}) #Could check if points are positive -class EntityLocation(pydantic_compat.BaseModel): +class EntityLocation(BaseModel): start: int end: int class NDTextEntity(NDBaseTool): ontology_type: Literal["named-entity"] = "named-entity" - location: EntityLocation = pydantic_compat.Field(determinant=True) + location: EntityLocation = Field(json_schema_extra={"determinant": True}) - @pydantic_compat.validator('location') + @field_validator('location') def is_valid_location(cls, v): - if isinstance(v, pydantic_compat.BaseModel): + if isinstance(v, BaseModel): v = v.dict() if len(v) < 2: @@ -843,11 +839,11 @@ def is_valid_location(cls, v): return v -class RLEMaskFeatures(pydantic_compat.BaseModel): +class RLEMaskFeatures(BaseModel): counts: List[int] size: List[int] - @pydantic_compat.validator('counts') + @field_validator('counts') def validate_counts(cls, counts): if not all([count >= 0 for count in counts]): raise ValueError( @@ -855,7 +851,7 @@ def validate_counts(cls, counts): ) return counts - @pydantic_compat.validator('size') + @field_validator('size') def validate_size(cls, size): if len(size) != 2: raise ValueError( @@ -867,16 +863,16 @@ def validate_size(cls, size): return size -class PNGMaskFeatures(pydantic_compat.BaseModel): +class PNGMaskFeatures(BaseModel): # base64 encoded png bytes png: str -class URIMaskFeatures(pydantic_compat.BaseModel): +class URIMaskFeatures(BaseModel): instanceURI: str colorRGB: Union[List[int], Tuple[int, int, int]] - @pydantic_compat.validator('colorRGB') + @field_validator('colorRGB') def validate_color(cls, colorRGB): #Does the dtype matter? Can it be a float? if not isinstance(colorRGB, (tuple, list)): @@ -896,7 +892,7 @@ def validate_color(cls, colorRGB): class NDMask(NDBaseTool): ontology_type: Literal["superpixel"] = "superpixel" mask: Union[URIMaskFeatures, PNGMaskFeatures, - RLEMaskFeatures] = pydantic_compat.Field(determinant=True) + RLEMaskFeatures] = Field(json_schema_extra={"determinant": True}) #A union with custom construction logic to improve error messages diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 0ecfa45c8..739475322 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -14,7 +14,7 @@ from pydantic.alias_generators import to_camel from labelbox.schema.ontology import SchemaId -from labelbox.utils import _CamelCaseMixin, camel_case, format_iso_datetime, format_iso_from_string +from labelbox.utils import _CamelCaseMixin, format_iso_datetime, format_iso_from_string class DataRowMetadataKind(Enum): @@ -67,9 +67,7 @@ class DataRowMetadata(_CamelCaseMixin): class DeleteDataRowMetadata(_CamelCaseMixin): data_row_id: Union[str, UniqueId, GlobalKey] fields: List[SchemaId] - - class Config: - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed = True) class DataRowMetadataBatchResponse(_CamelCaseMixin): @@ -577,7 +575,7 @@ def _batch_upsert( fields=list( chain.from_iterable( self._parse_upsert(f, m.data_row_id) - for f in m.fields))).dict(by_alias=True)) + for f in m.fields))).model_dump(by_alias=True)) res = _batch_operations(_batch_upsert, items, self._batch_size) return res @@ -796,7 +794,7 @@ def _upsert_schema( } }""" res = self._client.execute( - query, {"data": upsert_schema.dict(exclude_none=True) + query, {"data": upsert_schema.model_dump(exclude_none=True) })['upsertCustomMetadataSchema'] self.refresh_ontology() return _parse_metadata_schema(res) @@ -886,7 +884,7 @@ def _validate_delete(self, delete: DeleteDataRowMetadata): return _DeleteBatchDataRowMetadata( data_row_identifier=delete.data_row_id, - schema_ids=list(delete.fields)).dict(by_alias=True) + schema_ids=list(delete.fields)).model_dump(by_alias=True) def _validate_custom_schema_by_name(self, name: str) -> DataRowMetadataSchema: diff --git a/libs/labelbox/src/labelbox/schema/dataset.py b/libs/labelbox/src/labelbox/schema/dataset.py index 3d026a623..eaa37c5b7 100644 --- a/libs/labelbox/src/labelbox/schema/dataset.py +++ b/libs/labelbox/src/labelbox/schema/dataset.py @@ -22,7 +22,6 @@ from labelbox.orm import query from labelbox.exceptions import MalformedQueryException from labelbox.pagination import PaginatedCollection -from labelbox.pydantic_compat import BaseModel from labelbox.schema.data_row import DataRow from labelbox.schema.embedding import EmbeddingVector from labelbox.schema.export_filters import DatasetExportFilters, build_filters @@ -595,7 +594,7 @@ def _exec_upsert_data_rows( file_upload_thread_count=file_upload_thread_count, max_chunk_size_bytes=UPSERT_CHUNK_SIZE_BYTES) - data = json.dumps(manifest.dict()).encode("utf-8") + data = json.dumps(manifest.model_dump()).encode("utf-8") manifest_uri = self.client.upload_data(data, content_type="application/json", filename="manifest.json") diff --git a/libs/labelbox/src/labelbox/schema/embedding.py b/libs/labelbox/src/labelbox/schema/embedding.py index 1d71ba908..dbdf0c595 100644 --- a/libs/labelbox/src/labelbox/schema/embedding.py +++ b/libs/labelbox/src/labelbox/schema/embedding.py @@ -1,7 +1,7 @@ from typing import Optional, Callable, Dict, Any, List from labelbox.adv_client import AdvClient -from labelbox.pydantic_compat import BaseModel, PrivateAttr +from pydantic import BaseModel, PrivateAttr class EmbeddingVector(BaseModel): diff --git a/libs/labelbox/src/labelbox/schema/foundry/model.py b/libs/labelbox/src/labelbox/schema/foundry/model.py index 16ccae422..87fda22f2 100644 --- a/libs/labelbox/src/labelbox/schema/foundry/model.py +++ b/libs/labelbox/src/labelbox/schema/foundry/model.py @@ -1,12 +1,12 @@ from labelbox.utils import _CamelCaseMixin -from labelbox import pydantic_compat from datetime import datetime from typing import Dict +from pydantic import BaseModel -class Model(_CamelCaseMixin, pydantic_compat.BaseModel): +class Model(_CamelCaseMixin, BaseModel): id: str description: str inference_params_json_schema: Dict @@ -15,4 +15,4 @@ class Model(_CamelCaseMixin, pydantic_compat.BaseModel): created_at: datetime -MODEL_FIELD_NAMES = list(Model.schema()['properties'].keys()) +MODEL_FIELD_NAMES = list(Model.model_json_schema()['properties'].keys()) diff --git a/libs/labelbox/src/labelbox/schema/internal/data_row_uploader.py b/libs/labelbox/src/labelbox/schema/internal/data_row_uploader.py index 7d4224eb9..62962d70d 100644 --- a/libs/labelbox/src/labelbox/schema/internal/data_row_uploader.py +++ b/libs/labelbox/src/labelbox/schema/internal/data_row_uploader.py @@ -2,12 +2,12 @@ from typing import List -from labelbox import pydantic_compat from labelbox.schema.internal.data_row_upsert_item import DataRowItemBase, DataRowUpsertItem, DataRowCreateItem from labelbox.schema.internal.descriptor_file_creator import DescriptorFileCreator +from pydantic import BaseModel -class UploadManifest(pydantic_compat.BaseModel): +class UploadManifest(BaseModel): source: str item_count: int chunk_uris: List[str] diff --git a/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py b/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py index d3cc60483..5759ca818 100644 --- a/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py +++ b/libs/labelbox/src/labelbox/schema/internal/data_row_upsert_item.py @@ -2,7 +2,6 @@ from typing import List, Tuple, Optional -from labelbox.pydantic_compat import BaseModel from labelbox.schema.identifiable import UniqueId, GlobalKey from labelbox.schema.data_row import DataRow from pydantic import BaseModel diff --git a/libs/labelbox/src/labelbox/schema/label_score.py b/libs/labelbox/src/labelbox/schema/label_score.py index 9197f6b55..dba9d9639 100644 --- a/libs/labelbox/src/labelbox/schema/label_score.py +++ b/libs/labelbox/src/labelbox/schema/label_score.py @@ -1,7 +1,7 @@ -from labelbox import pydantic_compat +from pydantic import BaseModel -class LabelScore(pydantic_compat.BaseModel): +class LabelScore(BaseModel): """ A label score. diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 152d5a5a8..34e258de1 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -10,12 +10,11 @@ from labelbox.exceptions import InconsistentOntologyException from labelbox.orm.db_object import DbObject from labelbox.orm.model import Field, Relationship -from labelbox import pydantic_compat import json from pydantic import StringConstraints -FeatureSchemaId: Type[str] = pydantic_compat.constr(min_length=25, - max_length=25) +FeatureSchemaId: Type[str] = Annotated[str, StringConstraints(min_length=25, + max_length=25)] SchemaId: Type[str] = Annotated[str, StringConstraints(min_length=25, max_length=25)] diff --git a/libs/labelbox/src/labelbox/schema/project_overview.py b/libs/labelbox/src/labelbox/schema/project_overview.py index 3e75e7282..9f6c31e02 100644 --- a/libs/labelbox/src/labelbox/schema/project_overview.py +++ b/libs/labelbox/src/labelbox/schema/project_overview.py @@ -1,6 +1,6 @@ from typing import Dict, List -from labelbox.pydantic_compat import BaseModel from typing_extensions import TypedDict +from pydantic import BaseModel class ProjectOverview(BaseModel): """ diff --git a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py index f86844fda..07e1285bd 100644 --- a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py +++ b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py @@ -3,15 +3,16 @@ from typing import Optional, Dict from labelbox.schema.conflict_resolution_strategy import ConflictResolutionStrategy -from labelbox import pydantic_compat if sys.version_info >= (3, 8): from typing import TypedDict else: from typing_extensions import TypedDict +from pydantic import BaseModel, model_validator -class SendToAnnotateFromCatalogParams(pydantic_compat.BaseModel): + +class SendToAnnotateFromCatalogParams(BaseModel): """ Extra parameters for sending data rows to a project through catalog. At least one of source_model_run_id or source_project_id must be provided. @@ -40,7 +41,7 @@ class SendToAnnotateFromCatalogParams(pydantic_compat.BaseModel): ConflictResolutionStrategy] = ConflictResolutionStrategy.KeepExisting batch_priority: Optional[int] = 5 - @pydantic_compat.root_validator + @model_validator(mode="after") def check_project_id_or_model_run_id(cls, values): if not values.get("source_model_run_id") and not values.get("source_project_id"): raise ValueError( diff --git a/libs/labelbox/src/labelbox/schema/user_group.py b/libs/labelbox/src/labelbox/schema/user_group.py index e09c1768e..91cdb159c 100644 --- a/libs/labelbox/src/labelbox/schema/user_group.py +++ b/libs/labelbox/src/labelbox/schema/user_group.py @@ -4,13 +4,13 @@ from labelbox import Client from labelbox.exceptions import ResourceCreationError -from labelbox.pydantic_compat import BaseModel from labelbox.schema.user import User from labelbox.schema.project import Project from labelbox.exceptions import UnprocessableEntityError, MalformedQueryException, ResourceNotFoundError from labelbox.schema.queue_mode import QueueMode from labelbox.schema.ontology_kind import EditorTaskType from labelbox.schema.media_type import MediaType +from pydantic import BaseModel, ConfigDict class UserGroupColor(Enum): @@ -65,10 +65,8 @@ class UserGroup(BaseModel): users: Set[User] projects: Set[Project] client: Client - - class Config: - # fix for pydnatic 2 - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed = True) + def __init__( self, diff --git a/libs/labelbox/src/labelbox/utils.py b/libs/labelbox/src/labelbox/utils.py index 30e335be2..1feed1552 100644 --- a/libs/labelbox/src/labelbox/utils.py +++ b/libs/labelbox/src/labelbox/utils.py @@ -6,7 +6,7 @@ from dateutil.utils import default_tzinfo from urllib.parse import urlparse -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, model_serializer from pydantic.alias_generators import to_camel UPPERCASE_COMPONENTS = ['uri', 'rgb'] @@ -81,9 +81,9 @@ class ConversationData(BaseData, _NoCoercionMixin): class_name: Literal["ConversationData"] = "ConversationData" """ - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) res.pop('class_name') return res diff --git a/libs/labelbox/tests/data/annotation_types/data/test_raster.py b/libs/labelbox/tests/data/annotation_types/data/test_raster.py index 40c8d5648..4ce787022 100644 --- a/libs/labelbox/tests/data/annotation_types/data/test_raster.py +++ b/libs/labelbox/tests/data/annotation_types/data/test_raster.py @@ -6,11 +6,11 @@ from PIL import Image from labelbox.data.annotation_types.data import ImageData -from labelbox import pydantic_compat +from pydantic import ValidationError def test_validate_schema(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): data = ImageData() diff --git a/libs/labelbox/tests/data/annotation_types/data/test_text.py b/libs/labelbox/tests/data/annotation_types/data/test_text.py index 970b8382b..0af0a37fb 100644 --- a/libs/labelbox/tests/data/annotation_types/data/test_text.py +++ b/libs/labelbox/tests/data/annotation_types/data/test_text.py @@ -3,11 +3,11 @@ import pytest from labelbox.data.annotation_types import TextData -from labelbox import pydantic_compat +from pydantic import ValidationError def test_validate_schema(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): data = TextData() diff --git a/libs/labelbox/tests/data/annotation_types/data/test_video.py b/libs/labelbox/tests/data/annotation_types/data/test_video.py index f0e42b83f..d0e5ed012 100644 --- a/libs/labelbox/tests/data/annotation_types/data/test_video.py +++ b/libs/labelbox/tests/data/annotation_types/data/test_video.py @@ -2,11 +2,11 @@ import pytest from labelbox.data.annotation_types import VideoData -from labelbox import pydantic_compat +from pydantic import ValidationError def test_validate_schema(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): data = VideoData() diff --git a/libs/labelbox/tests/data/annotation_types/geometry/test_line.py b/libs/labelbox/tests/data/annotation_types/geometry/test_line.py index f0d0673df..10362e728 100644 --- a/libs/labelbox/tests/data/annotation_types/geometry/test_line.py +++ b/libs/labelbox/tests/data/annotation_types/geometry/test_line.py @@ -2,14 +2,14 @@ import cv2 from labelbox.data.annotation_types.geometry import Point, Line -from labelbox import pydantic_compat +from pydantic import ValidationError def test_line(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): line = Line() - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): line = Line(points=[[0, 1], [2, 3]]) points = [[0, 1], [0, 2], [2, 2]] diff --git a/libs/labelbox/tests/data/annotation_types/geometry/test_mask.py b/libs/labelbox/tests/data/annotation_types/geometry/test_mask.py index 7a2b713ee..960e64d9a 100644 --- a/libs/labelbox/tests/data/annotation_types/geometry/test_mask.py +++ b/libs/labelbox/tests/data/annotation_types/geometry/test_mask.py @@ -4,11 +4,11 @@ import cv2 from labelbox.data.annotation_types import Point, Rectangle, Mask, MaskData -from labelbox import pydantic_compat +from pydantic import ValidationError def test_mask(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): mask = Mask() mask_data = np.zeros((32, 32, 3), dtype=np.uint8) diff --git a/libs/labelbox/tests/data/annotation_types/geometry/test_point.py b/libs/labelbox/tests/data/annotation_types/geometry/test_point.py index 47c152d2b..bca3900d2 100644 --- a/libs/labelbox/tests/data/annotation_types/geometry/test_point.py +++ b/libs/labelbox/tests/data/annotation_types/geometry/test_point.py @@ -2,11 +2,11 @@ import cv2 from labelbox.data.annotation_types import Point -from labelbox import pydantic_compat +from pydantic import ValidationError def test_point(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): line = Point() with pytest.raises(TypeError): diff --git a/libs/labelbox/tests/data/annotation_types/geometry/test_polygon.py b/libs/labelbox/tests/data/annotation_types/geometry/test_polygon.py index 8a7525e8f..084349023 100644 --- a/libs/labelbox/tests/data/annotation_types/geometry/test_polygon.py +++ b/libs/labelbox/tests/data/annotation_types/geometry/test_polygon.py @@ -2,17 +2,16 @@ import cv2 from labelbox.data.annotation_types import Polygon, Point -from labelbox import pydantic_compat - +from pydantic import ValidationError def test_polygon(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): polygon = Polygon() - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): polygon = Polygon(points=[[0, 1], [2, 3]]) - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): polygon = Polygon(points=[Point(x=0, y=1), Point(x=0, y=1)]) points = [[0., 1.], [0., 2.], [2., 2.], [2., 0.]] diff --git a/libs/labelbox/tests/data/annotation_types/geometry/test_rectangle.py b/libs/labelbox/tests/data/annotation_types/geometry/test_rectangle.py index 3c01ef6ed..d1d7331d6 100644 --- a/libs/labelbox/tests/data/annotation_types/geometry/test_rectangle.py +++ b/libs/labelbox/tests/data/annotation_types/geometry/test_rectangle.py @@ -2,11 +2,11 @@ import pytest from labelbox.data.annotation_types import Point, Rectangle -from labelbox import pydantic_compat +from pydantic import ValidationError def test_rectangle(): - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): rectangle = Rectangle() rectangle = Rectangle(start=Point(x=0, y=1), end=Point(x=10, y=10)) diff --git a/libs/labelbox/tests/data/annotation_types/test_annotation.py b/libs/labelbox/tests/data/annotation_types/test_annotation.py index b6dc00041..38a907489 100644 --- a/libs/labelbox/tests/data/annotation_types/test_annotation.py +++ b/libs/labelbox/tests/data/annotation_types/test_annotation.py @@ -7,7 +7,7 @@ from labelbox.data.annotation_types.geometry.rectangle import Rectangle from labelbox.data.annotation_types.video import VideoClassificationAnnotation from labelbox.exceptions import ConfidenceNotSupportedException -from labelbox import pydantic_compat +from pydantic import ValidationError def test_annotation(): @@ -19,7 +19,7 @@ def test_annotation(): value=line, name=name, ) - assert annotation.value.points[0].dict() == {'extra': {}, 'x': 1., 'y': 2.} + assert annotation.value.points[0].model_dump() == {'extra': {}, 'x': 1., 'y': 2.} assert annotation.name == name # Check ner @@ -35,7 +35,7 @@ def test_annotation(): ) # Invalid subclass - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): ObjectAnnotation( value=line, name=name, @@ -56,11 +56,11 @@ def test_video_annotations(): line = Line(points=[Point(x=1, y=2), Point(x=2, y=2)]) # Wrong type - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): VideoClassificationAnnotation(value=line, name=name, frame=1) # Missing frames - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): VideoClassificationAnnotation(value=line, name=name) VideoObjectAnnotation(value=line, name=name, keyframe=True, frame=2) diff --git a/libs/labelbox/tests/data/annotation_types/test_label.py b/libs/labelbox/tests/data/annotation_types/test_label.py index a6947cd4b..8d8f8c836 100644 --- a/libs/labelbox/tests/data/annotation_types/test_label.py +++ b/libs/labelbox/tests/data/annotation_types/test_label.py @@ -1,4 +1,4 @@ -from labelbox.pydantic_compat import ValidationError +from pydantic import ValidationError import numpy as np import labelbox.types as lb_types diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index db771f806..24dc1b9b2 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -4,7 +4,7 @@ from labelbox.data.annotation_types.metrics import ConfusionMatrixMetric, ScalarMetric from labelbox.data.annotation_types import ScalarMetric, Label, ImageData from labelbox.data.annotation_types.metrics.scalar import RESERVED_METRIC_NAMES -from labelbox import pydantic_compat +from pydantic import ValidationError def test_legacy_scalar_metric(): @@ -159,19 +159,19 @@ def test_custom_confusison_matrix_metric(feature_name, subclass_name, def test_name_exists(): # Name is only required for ConfusionMatrixMetric for now. - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric(value=[0, 1, 2, 3]) assert "field required (type=value_error.missing)" in str(exc_info.value) def test_invalid_aggregations(): - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ScalarMetric( metric_name="invalid aggregation", value=0.1, aggregation=ConfusionMatrixAggregation.CONFUSION_MATRIX) assert "value is not a valid enumeration member" in str(exc_info.value) - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric(metric_name="invalid aggregation", value=[0, 1, 2, 3], aggregation=ScalarMetricAggregation.SUM) @@ -179,18 +179,18 @@ def test_invalid_aggregations(): def test_invalid_number_of_confidence_scores(): - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ScalarMetric(metric_name="too few scores", value={0.1: 0.1}) assert "Number of confidence scores must be greater" in str(exc_info.value) - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric(metric_name="too few scores", value={0.1: [0, 1, 2, 3]}) assert "Number of confidence scores must be greater" in str(exc_info.value) - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ScalarMetric(metric_name="too many scores", value={i / 20.: 0.1 for i in range(20)}) assert "Number of confidence scores must be greater" in str(exc_info.value) - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric( metric_name="too many scores", value={i / 20.: [0, 1, 2, 3] for i in range(20)}) @@ -199,6 +199,6 @@ def test_invalid_number_of_confidence_scores(): @pytest.mark.parametrize("metric_name", RESERVED_METRIC_NAMES) def test_reserved_names(metric_name: str): - with pytest.raises(pydantic_compat.ValidationError) as exc_info: + with pytest.raises(ValidationError) as exc_info: ScalarMetric(metric_name=metric_name, value=0.5) assert 'is a reserved metric name' in exc_info.value.errors()[0]['msg'] diff --git a/libs/labelbox/tests/data/annotation_types/test_tiled_image.py b/libs/labelbox/tests/data/annotation_types/test_tiled_image.py index cd96fee6d..aea6587f6 100644 --- a/libs/labelbox/tests/data/annotation_types/test_tiled_image.py +++ b/libs/labelbox/tests/data/annotation_types/test_tiled_image.py @@ -7,7 +7,7 @@ TileLayer, TiledImageData, EPSGTransformer) -from labelbox import pydantic_compat +from pydantic import ValidationError @pytest.mark.parametrize("epsg", list(EPSG)) @@ -28,7 +28,7 @@ def test_tiled_bounds(epsg): @pytest.mark.parametrize("epsg", list(EPSG)) def test_tiled_bounds_same(epsg): single_bound = Point(x=0, y=0) - with pytest.raises(pydantic_compat.ValidationError): + with pytest.raises(ValidationError): tiled_bounds = TiledBounds(epsg=epsg, bounds=[single_bound, single_bound]) From 06f1a5518baf5d2d53a294ab47a9ca08649b2d85 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:46:55 -0500 Subject: [PATCH 11/34] fixed tests --- libs/labelbox/pyproject.toml | 2 +- .../data/annotation_types/metrics/scalar.py | 2 +- .../labelbox/schema/bulk_import_request.py | 26 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index 35865e6f5..e8e9e3110 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -86,7 +86,7 @@ unit = "pytest tests/unit" # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/data" } +data = { cmd = "pytest tests/data/annotation_import/test_ndjson_validation.py::test_video_upload[MediaType.Video]" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index b82ecefcd..8795afd85 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -33,7 +33,7 @@ class ScalarMetric(BaseMetric): value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN - @field_validator.validator('metric_name') + @field_validator('metric_name') def validate_metric_name(cls, name: Union[str, None]): if name is None: return None diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index d744ee528..919edc9ec 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -8,19 +8,19 @@ from google.api_core import retry from labelbox import parser import requests -from pydantic import ValidationError, BaseModel, Field, field_validator, model_validator, ConfigDict -from typing_extensions import Literal +from pydantic import ValidationError, BaseModel, Field, field_validator, model_validator, ConfigDict, StringConstraints +from typing_extensions import Literal, Annotated from typing import (Any, List, Optional, BinaryIO, Dict, Iterable, Tuple, Union, Type, Set, TYPE_CHECKING) from labelbox import exceptions as lb_exceptions -from labelbox.orm.model import Entity from labelbox import utils from labelbox.orm import query from labelbox.orm.db_object import DbObject -from labelbox.orm.model import Field, Relationship +from labelbox.orm.model import Relationship from labelbox.schema.enums import BulkImportRequestState from labelbox.schema.serialization import serialize_labels +from labelbox.orm.model import Field as lb_Field if TYPE_CHECKING: from labelbox import Project @@ -34,7 +34,7 @@ def _determinants(parent_cls: Any) -> List[str]: return [ k for k, v in parent_cls.model_fields.items() - if 'determinant' in v.field_info.extra + if v.json_schema_extra and "determinant" in v.json_schema_extra ] @@ -101,12 +101,12 @@ class BulkImportRequest(DbObject): project (Relationship): `ToOne` relationship to Project created_by (Relationship): `ToOne` relationship to User """ - name = Field.String("name") - state = Field.Enum(BulkImportRequestState, "state") - input_file_url = Field.String("input_file_url") - error_file_url = Field.String("error_file_url") - status_file_url = Field.String("status_file_url") - created_at = Field.DateTime("created_at") + name = lb_Field.String("name") + state = lb_Field.Enum(BulkImportRequestState, "state") + input_file_url = lb_Field.String("input_file_url") + error_file_url = lb_Field.String("error_file_url") + status_file_url = lb_Field.String("status_file_url") + created_at = lb_Field.DateTime("created_at") project = Relationship.ToOne("Project") created_by = Relationship.ToOne("User", False, "created_by") @@ -513,7 +513,7 @@ def get_mal_schemas(ontology): return valid_feature_schemas_by_schema_id, valid_feature_schemas_by_name -LabelboxID: str = Field(..., min_length=25, max_length=25) +LabelboxID: str = Annotated[str, StringConstraints(min_length=25, max_length=25)] class Bbox(BaseModel): @@ -627,7 +627,7 @@ class NDFeatureSchema(BaseModel): @model_validator(mode="after") def must_set_one(cls, values): - if values['schemaId'] is None and values['name'] is None: + if values.schemaId is None and values.name is None: raise ValueError( "Must set either schemaId or name for all feature schemas") return values From 212cf469068225dcd09113edf71ca8df9be1e59d Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 21:03:30 -0500 Subject: [PATCH 12/34] removed gets --- libs/labelbox/pyproject.toml | 2 +- .../annotation_types/data/generic_data_row_data.py | 2 +- .../labelbox/data/annotation_types/data/raster.py | 12 ++++++------ .../src/labelbox/data/annotation_types/data/text.py | 10 +++++----- .../data/annotation_types/data/tiled_image.py | 4 ++-- .../src/labelbox/data/annotation_types/data/video.py | 10 +++++----- .../data/annotation_types/ner/text_entity.py | 6 +++--- .../src/labelbox/data/annotation_types/video.py | 4 ++-- .../data/serialization/labelbox_v1/feature.py | 4 ++-- .../src/labelbox/data/serialization/ndjson/base.py | 5 ++--- .../data/serialization/ndjson/classification.py | 3 +-- .../src/labelbox/schema/send_to_annotate_params.py | 4 ++-- 12 files changed, 32 insertions(+), 34 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index e8e9e3110..35865e6f5 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -86,7 +86,7 @@ unit = "pytest tests/unit" # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/data/annotation_import/test_ndjson_validation.py::test_video_upload[MediaType.Video]" } +data = { cmd = "pytest tests/data" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py index 58eb07b9e..7c39bb6b7 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py @@ -17,7 +17,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> Optional[str]: @model_validator(mode="before") def validate_one_datarow_key_present(cls, data): keys = ['external_id', 'global_key', 'uid'] - count = sum([key in data for key in keys]) + count = sum([hasattr(data, key) for key in keys]) if count < 1: raise ValueError(f"Exactly one of {keys} must be present.") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index cf78aa0c5..015b21d1e 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -158,12 +158,12 @@ def create_url(self, signer: Callable[[bytes], str]) -> str: @model_validator(mode="after") def validate_args(cls, values): - file_path = values.get("file_path") - im_bytes = values.get("im_bytes") - url = values.get("url") - arr = values.get("arr") - uid = values.get('uid') - global_key = values.get('global_key') + file_path = values.file_path + im_bytes = values.im_bytes + url = values.url + arr = values.arr + uid = values.uid + global_key = values.global_key if uid == file_path == im_bytes == url == global_key == None and arr is None: raise ValueError( "One of `file_path`, `im_bytes`, `url`, `uid`, `global_key` or `arr` required." diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py index 9334524b3..1de158be5 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py @@ -93,11 +93,11 @@ def create_url(self, signer: Callable[[bytes], str]) -> None: @model_validator(mode="after") def validate_date(cls, values): - file_path = values.get("file_path") - text = values.get("text") - url = values.get("url") - uid = values.get('uid') - global_key = values.get('global_key') + file_path = values.file_path + text = values.text + url = values.url + uid = values.uid + global_key = values.global_key if uid == file_path == text == url == global_key == None: raise ValueError( "One of `file_path`, `text`, `uid`, `global_key` or `url` required." diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py index b370dfe29..d009a468d 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py @@ -68,8 +68,8 @@ def validate_bounds_not_equal(cls, bounds): #validate bounds are within lat,lng range if they are EPSG4326 @model_validator(mode="after") def validate_bounds_lat_lng(cls, values): - epsg = values.get('epsg') - bounds = values.get('bounds') + epsg = values.epsg + bounds = values.bounds if epsg == EPSG.EPSG4326: for bound in bounds: diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py index 2a26bf1ff..3edb975fa 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py @@ -152,11 +152,11 @@ def frames_to_video(self, @model_validator(mode="after") def validate_data(cls, values): - file_path = values.get("file_path") - url = values.get("url") - frames = values.get("frames") - uid = values.get("uid") - global_key = values.get("global_key") + file_path = values.file_path + url = values.url + frames = values.frames + uid = values.uid + global_key = values.global_key if uid == file_path == frames == url == global_key == None: raise ValueError( diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py index 4651ae0e3..84c4e66f2 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py @@ -11,9 +11,9 @@ class TextEntity(BaseModel): @model_validator(mode="after") def validate_start_end(cls, values): - if 'start' in values and 'end' in values: - if (isinstance(values['start'], int) and - values['start'] > values['end']): + if hasattr(values, 'start') and hasattr(values, 'end'): + if (isinstance(values.start, int) and + values.start > values.end): raise ValueError( "Location end must be greater or equal to start") return values diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index 776a998c9..41ea3491b 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -94,8 +94,8 @@ class MaskFrame(_CamelCaseMixin, BaseModel): @model_validator(mode="after") def validate_args(cls, values): - im_bytes = values.get("im_bytes") - instance_uri = values.get("instance_uri") + im_bytes = values.im_bytes + instance_uri = values.instance_uri if im_bytes == instance_uri == None: raise ValueError("One of `instance_uri`, `im_bytes` required.") diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py index 54d6b6459..a68a666a7 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py @@ -15,8 +15,8 @@ class LBV1Feature(BaseModel): @model_validator(mode = "after") def check_ids(cls, values): - if values.get('value') is None: - values['value'] = values['title'] + if values.value is None: + values.value = values.title return values @model_serializer(mode = "wrap") diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index 7fb5beee4..db796c34c 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -12,7 +12,7 @@ class DataRow(_CamelCaseMixin): @model_validator(mode="after") def must_set_one(cls, values): - if not is_exactly_one_set(values.get('id'), values.get('global_key')): + if not is_exactly_one_set(values.id, values.global_key): raise ValueError("Must set either id or global_key") return values @@ -44,8 +44,7 @@ class NDAnnotation(NDJsonBase): @model_validator(mode="after") def must_set_one(cls, values): - if ('schema_id' not in values or values['schema_id'] - is None) and ('name' not in values or values['name'] is None): + if (not hasattr(values, "schema_id") or values.schema_id is None) and (not hasattr(values, "name") or values.name is None): raise ValueError("Schema id or name are not set. Set either one.") return values diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index 2ed1a2f3c..0cb0e9cf9 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -21,8 +21,7 @@ class NDAnswer(ConfidenceMixin, CustomMetricsMixin): @model_validator(mode="after") def must_set_one(cls, values): - if ('schema_id' not in values or values['schema_id'] - is None) and ('name' not in values or values['name'] is None): + if (not hasattr(values, "schema_id") or values.schema_id is None) and (not hasattr(values, "name") or values.name is None): raise ValueError("Schema id or name are not set. Set either one.") return values diff --git a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py index 07e1285bd..516ae6d37 100644 --- a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py +++ b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py @@ -43,11 +43,11 @@ class SendToAnnotateFromCatalogParams(BaseModel): @model_validator(mode="after") def check_project_id_or_model_run_id(cls, values): - if not values.get("source_model_run_id") and not values.get("source_project_id"): + if not values.source_model_run_id and not values.source_project_id: raise ValueError( 'Either source_project_id or source_model_id are required' ) - if values.get("source_model_run_id") and values.get("source_project_id"): + if values.source_model_run_id and values.source_project_id: raise ValueError( 'Provide only a source_project_id or source_model_id not both' ) From 36353794493a4ee7a095dc073ad97d653b53c4dd Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sat, 20 Jul 2024 22:57:21 -0500 Subject: [PATCH 13/34] fixed a lot of tests --- .../data/generic_data_row_data.py | 2 +- .../labelbox/data/annotation_types/label.py | 4 ++- .../src/labelbox/schema/consensus_settings.py | 5 ++-- .../src/labelbox/schema/data_row_metadata.py | 26 +++++++++---------- .../labelbox/src/labelbox/schema/embedding.py | 2 +- libs/labelbox/src/labelbox/schema/project.py | 2 +- libs/labelbox/src/labelbox/utils.py | 4 +-- .../test_data_row_delete_metadata.py | 12 ++++----- 8 files changed, 30 insertions(+), 27 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py index 7c39bb6b7..58eb07b9e 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py @@ -17,7 +17,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> Optional[str]: @model_validator(mode="before") def validate_one_datarow_key_present(cls, data): keys = ['external_id', 'global_key', 'uid'] - count = sum([hasattr(data, key) for key in keys]) + count = sum([key in data for key in keys]) if count < 1: raise ValueError(f"Exactly one of {keys} must be present.") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/label.py b/libs/labelbox/src/labelbox/data/annotation_types/label.py index 37c909cd3..4e042ccf1 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/label.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/label.py @@ -57,7 +57,9 @@ class Label(BaseModel): @field_validator("data", mode="before") def validate_data(cls, data): if isinstance(data, Dict): - data["class_name"] = "GenericDataRowData" + return GenericDataRowData(**data) + elif isinstance(data, GenericDataRowData): + return data else: warnings.warn( f"Using {type(data).__name__} class for label.data is deprecated. " diff --git a/libs/labelbox/src/labelbox/schema/consensus_settings.py b/libs/labelbox/src/labelbox/schema/consensus_settings.py index bd9cfc047..e94c4b63f 100644 --- a/libs/labelbox/src/labelbox/schema/consensus_settings.py +++ b/libs/labelbox/src/labelbox/schema/consensus_settings.py @@ -1,4 +1,5 @@ from labelbox.utils import _CamelCaseMixin +from pydantic import Field, AliasChoices class ConsensusSettings(_CamelCaseMixin): @@ -14,5 +15,5 @@ class ConsensusSettings(_CamelCaseMixin): coverage_percentage: Percentage of data rows to be labeled more than once """ - number_of_labels: int - coverage_percentage: float + number_of_labels: int = Field(validation_alias=AliasChoices("numberOfLabels", "number_of_labels")) + coverage_percentage: float = Field(validation_alias=AliasChoices("coveragePercentage", "coverage_percentage")) diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 739475322..d4dca504a 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -10,7 +10,7 @@ from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey -from pydantic import BaseModel, Field, StringConstraints, ConfigDict, AliasGenerator, model_serializer, conlist +from pydantic import BaseModel, Field, StringConstraints, ConfigDict, AliasGenerator, model_serializer, conlist, AliasChoices from pydantic.alias_generators import to_camel from labelbox.schema.ontology import SchemaId @@ -29,9 +29,9 @@ class DataRowMetadataKind(Enum): # Metadata schema class DataRowMetadataSchema(BaseModel): uid: SchemaId - name: str = Annotated[str, StringConstraints(strip_whitespace=True, - min_length=1, - max_length=100)] + name: str = Field(strip_whitespace=True, + min_length=1, + max_length=100) reserved: bool kind: DataRowMetadataKind options: Optional[List["DataRowMetadataSchema"]] = None @@ -43,7 +43,7 @@ class DataRowMetadataSchema(BaseModel): Embedding: Type[List[float]] = conlist(float, min_length=128, max_length=128) -String: Type[str] = Annotated[str, StringConstraints(max_length=4096)] +String: Type[str] = Field(max_length=4096) # Metadata base class @@ -59,13 +59,13 @@ class DataRowMetadataField(BaseModel): class DataRowMetadata(_CamelCaseMixin): - global_key: Optional[str] = None - data_row_id: Optional[str] = None + global_key: Optional[str] = Field(default=None, validation_alias=AliasChoices("global_key", "globalKey")) + data_row_id: Optional[str] = Field(default=None, validation_alias=AliasChoices("data_row_id", "dataRowId")) fields: List[DataRowMetadataField] class DeleteDataRowMetadata(_CamelCaseMixin): - data_row_id: Union[str, UniqueId, GlobalKey] + data_row_id: Union[str, UniqueId, GlobalKey] = Field(validation_alias=AliasChoices("data_row_id", "dataRowId")) fields: List[SchemaId] model_config = ConfigDict(arbitrary_types_allowed = True) @@ -89,8 +89,8 @@ class _UpsertDataRowMetadataInput(_CamelCaseMixin): # Batch of upsert values for a datarow class _UpsertBatchDataRowMetadata(_CamelCaseMixin): - global_key: Optional[str] = None - data_row_id: Optional[str] = None + global_key: Optional[str] = Field(default=None, validation_alias=AliasChoices("global_key", "globalKey")) + data_row_id: Optional[str] = Field(default=None, validation_alias=AliasChoices("data_row_id", "dataRowId")) fields: List[_UpsertDataRowMetadataInput] @@ -961,10 +961,10 @@ def _validate_parse_text( raise ValueError( f"Expected a string type for the text field. Found {type(field.value)}" ) - - if len(field.value) > String.max_length: + print(String.metadata[0].max_length) + if len(field.value) > String.metadata[0].max_length: raise ValueError( - f"String fields cannot exceed {String.max_length} characters.") + f"String fields cannot exceed {String.metadata.max_length} characters.") return [field.model_dump(by_alias=True)] diff --git a/libs/labelbox/src/labelbox/schema/embedding.py b/libs/labelbox/src/labelbox/schema/embedding.py index dbdf0c595..a67b82d38 100644 --- a/libs/labelbox/src/labelbox/schema/embedding.py +++ b/libs/labelbox/src/labelbox/schema/embedding.py @@ -15,7 +15,7 @@ class EmbeddingVector(BaseModel): """ embedding_id: str vector: List[float] - clusters: Optional[List[int]] + clusters: Optional[List[int]] = None def to_gql(self) -> Dict[str, Any]: result = {"embeddingId": self.embedding_id, "vector": self.vector} diff --git a/libs/labelbox/src/labelbox/schema/project.py b/libs/labelbox/src/labelbox/schema/project.py index 2027877e2..f8873215b 100644 --- a/libs/labelbox/src/labelbox/schema/project.py +++ b/libs/labelbox/src/labelbox/schema/project.py @@ -935,7 +935,7 @@ def create_batch( dr_ids, global_keys, self._wait_processing_max_seconds) if consensus_settings: - consensus_settings = ConsensusSettings(**consensus_settings).dict( + consensus_settings = ConsensusSettings(**consensus_settings).model_dump( by_alias=True) if row_count >= MAX_SYNC_BATCH_ROW_COUNT: diff --git a/libs/labelbox/src/labelbox/utils.py b/libs/labelbox/src/labelbox/utils.py index 1feed1552..b98011abe 100644 --- a/libs/labelbox/src/labelbox/utils.py +++ b/libs/labelbox/src/labelbox/utils.py @@ -6,8 +6,8 @@ from dateutil.utils import default_tzinfo from urllib.parse import urlparse -from pydantic import BaseModel, ConfigDict, model_serializer -from pydantic.alias_generators import to_camel +from pydantic import BaseModel, ConfigDict, model_serializer, AliasGenerator, AliasChoices +from pydantic.alias_generators import to_camel, to_pascal UPPERCASE_COMPONENTS = ['uri', 'rgb'] ISO_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ' diff --git a/libs/labelbox/tests/integration/test_data_row_delete_metadata.py b/libs/labelbox/tests/integration/test_data_row_delete_metadata.py index 6c3928617..8674beb33 100644 --- a/libs/labelbox/tests/integration/test_data_row_delete_metadata.py +++ b/libs/labelbox/tests/integration/test_data_row_delete_metadata.py @@ -1,9 +1,9 @@ -from datetime import datetime +from datetime import datetime, timezone import uuid import pytest -from labelbox import DataRow, Dataset +from labelbox import DataRow, Dataset, Client, DataRowMetadataOntology from labelbox.exceptions import MalformedQueryException from labelbox.schema.data_row_metadata import DataRowMetadataField, DataRowMetadata, DataRowMetadataKind, DeleteDataRowMetadata from labelbox.schema.identifiable import GlobalKey, UniqueId @@ -27,7 +27,7 @@ @pytest.fixture -def mdo(client): +def mdo(client: Client): mdo = client.get_data_row_metadata_ontology() try: mdo.create_schema(CUSTOM_TEXT_SCHEMA_NAME, DataRowMetadataKind.string) @@ -56,7 +56,7 @@ def big_dataset(dataset: Dataset, image_url): def make_metadata(dr_id: str = None, gk: str = None) -> DataRowMetadata: msg = "A message" - time = datetime.utcnow() + time = datetime.now(timezone.utc) metadata = DataRowMetadata( global_key=gk, @@ -72,7 +72,7 @@ def make_metadata(dr_id: str = None, gk: str = None) -> DataRowMetadata: def make_named_metadata(dr_id) -> DataRowMetadata: msg = "A message" - time = datetime.utcnow() + time = datetime.now(timezone.utc) metadata = DataRowMetadata(data_row_id=dr_id, fields=[ @@ -233,7 +233,7 @@ def test_large_bulk_delete_datarow_metadata(data_rows_for_delete, big_dataset, 'data_row_for_delete', ['data_row_id_as_str', 'data_row_unique_id', 'data_row_global_key']) def test_bulk_delete_datarow_enum_metadata(data_row_for_delete, - data_row: DataRow, mdo, request): + data_row: DataRow, mdo: DataRowMetadataOntology, request): """test bulk deletes for non non fields""" metadata = make_metadata(data_row.uid) metadata.fields = [ From b26bbeceeacb113ffdc02d6e9e47c90b4c51f09c Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:25:51 -0500 Subject: [PATCH 14/34] finished serilazation tests --- .../data/annotation_types/annotation.py | 3 +- .../data/annotation_types/base_annotation.py | 4 +- .../classification/classification.py | 4 +- .../annotation_types/data/conversation.py | 2 +- .../data/annotation_types/data/raster.py | 2 + .../labelbox/data/annotation_types/label.py | 9 +- .../data/annotation_types/metrics/scalar.py | 2 +- .../labelbox/data/annotation_types/types.py | 10 - .../labelbox/data/annotation_types/video.py | 13 +- libs/labelbox/src/labelbox/data/mixins.py | 6 - .../data/serialization/coco/converter.py | 4 +- .../labelbox_v1/classification.py | 22 +- .../serialization/labelbox_v1/converter.py | 2 +- .../data/serialization/labelbox_v1/label.py | 4 +- .../data/serialization/labelbox_v1/objects.py | 8 +- .../data/serialization/ndjson/base.py | 33 +- .../serialization/ndjson/classification.py | 61 +-- .../data/serialization/ndjson/converter.py | 14 +- .../data/serialization/ndjson/label.py | 51 ++- .../data/serialization/ndjson/metric.py | 20 +- .../data/serialization/ndjson/objects.py | 38 +- .../data/serialization/ndjson/relationship.py | 4 +- .../src/labelbox/pydantic_serializers.py | 42 +- .../labelbox/schema/bulk_import_request.py | 6 +- .../src/labelbox/schema/consensus_settings.py | 4 +- .../src/labelbox/schema/data_row_metadata.py | 16 +- .../src/labelbox/schema/export_task.py | 4 +- .../src/labelbox/schema/foundry/app.py | 9 +- .../labelbox/schema/foundry/foundry_client.py | 2 +- libs/labelbox/src/labelbox/schema/ontology.py | 16 +- libs/labelbox/src/labelbox/schema/project.py | 4 +- libs/labelbox/src/labelbox/utils.py | 2 +- libs/labelbox/tests/conftest.py | 3 - .../data/annotation_types/test_metrics.py | 6 +- .../tests/data/annotation_types/test_video.py | 4 +- .../classification_import_global_key.json | 4 +- .../data/assets/ndjson/metric_import.json | 11 +- .../ndjson/metric_import_global_key.json | 11 +- .../data/assets/ndjson/video_import.json | 362 ++++++++++-------- .../assets/ndjson/video_import_name_only.json | 362 ++++++++++-------- .../serialization/ndjson/test_checklist.py | 17 +- .../serialization/ndjson/test_conversation.py | 2 +- .../serialization/ndjson/test_data_gen.py | 6 +- .../data/serialization/ndjson/test_dicom.py | 18 +- .../serialization/ndjson/test_document.py | 3 +- .../data/serialization/ndjson/test_radio.py | 11 +- .../data/serialization/ndjson/test_video.py | 85 ++-- libs/labelbox/tests/integration/conftest.py | 3 - .../tests/integration/test_foundry.py | 8 +- ...est_unit_delete_batch_data_row_metadata.py | 8 +- 50 files changed, 733 insertions(+), 612 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/annotation.py b/libs/labelbox/src/labelbox/data/annotation_types/annotation.py index 9fa77a38a..8a718751a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/annotation.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/annotation.py @@ -7,6 +7,7 @@ from labelbox.data.annotation_types.classification.classification import ClassificationAnnotation from .ner import DocumentEntity, TextEntity, ConversationEntity +from typing import Optional class ObjectAnnotation(BaseAnnotation, ConfidenceMixin, CustomMetricsMixin): @@ -29,4 +30,4 @@ class ObjectAnnotation(BaseAnnotation, ConfidenceMixin, CustomMetricsMixin): """ value: Union[TextEntity, ConversationEntity, DocumentEntity, Geometry] - classifications: List[ClassificationAnnotation] = [] + classifications: Optional[List[ClassificationAnnotation]] = [] diff --git a/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py b/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py index b7c510083..27e66c063 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/base_annotation.py @@ -3,7 +3,7 @@ from typing import Any, Dict, Optional from .feature import FeatureSchema -from pydantic import PrivateAttr +from pydantic import PrivateAttr, ConfigDict class BaseAnnotation(FeatureSchema, abc.ABC): @@ -11,6 +11,8 @@ class BaseAnnotation(FeatureSchema, abc.ABC): """ _uuid: Optional[UUID] = PrivateAttr() extra: Dict[str, Any] = {} + + model_config = ConfigDict(extra="allow") def __init__(self, **data): super().__init__(**data) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py index 0cda0a2ed..80c515b48 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py @@ -26,7 +26,7 @@ class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): """ extra: Dict[str, Any] = {} keyframe: Optional[bool] = None - classifications: List['ClassificationAnnotation'] = [] + classifications: Optional[List['ClassificationAnnotation']] = None @model_serializer(mode="wrap") def serialize_model(self, handler): @@ -84,7 +84,7 @@ class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, name (Optional[str]) classifications (Optional[List[ClassificationAnnotation]]): Optional sub classification of the annotation feature_schema_id (Optional[Cuid]) - value (Union[Text, Checklist, Radio, Dropdown]) + value (Union[Text, Checklist, Radio]) extra (Dict[str, Any]) """ diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py b/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py index 302b2c487..99078c48c 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py @@ -4,4 +4,4 @@ class ConversationData(BaseData): - class_name: Literal["ConversationData"] = "ConversationData" \ No newline at end of file + pass \ No newline at end of file diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index 015b21d1e..5225ca37a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -21,6 +21,8 @@ class RasterData(BaseModel, ABC): im_bytes: Optional[bytes] = None file_path: Optional[str] = None url: Optional[str] = None + uid: Optional[str] = None + global_key: Optional[str] = None arr: Optional[TypedArray[Literal['uint8']]] = None model_config = ConfigDict(extra="forbid", copy_on_model_validation="none") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/label.py b/libs/labelbox/src/labelbox/data/annotation_types/label.py index 4e042ccf1..9cd3dce05 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/label.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/label.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Any, Callable, Dict, List, Union, Optional +from typing import Any, Callable, Dict, List, Union, Optional, get_args import warnings import labelbox @@ -17,7 +17,8 @@ from .video import VideoClassificationAnnotation from .video import VideoObjectAnnotation, VideoMaskAnnotation from ..ontology import get_feature_schema_lookup -from pydantic import BaseModel, field_validator +from pydantic import BaseModel, field_validator, model_serializer +from labelbox.pydantic_serializers import _feature_serializer DataType = Union[VideoData, ImageData, TextData, TiledImageData, AudioData, ConversationData, DicomData, DocumentData, HTMLData, @@ -207,8 +208,8 @@ def _assign_option(self, classification: ClassificationAnnotation, @field_validator("annotations", mode="before") def validate_union(cls, value): supported = tuple([ - field.type_ - for field in cls.model_fields['annotations'].sub_fields[0].sub_fields + field + for field in get_args(get_args(cls.model_fields['annotations'].annotation)[0]) ]) if not isinstance(value, list): raise TypeError(f"Annotations must be a list. Found {type(value)}") diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 8795afd85..8c1ea5216 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -44,7 +44,7 @@ def validate_metric_name(cls, name: Union[str, None]): return name @model_serializer(mode="wrap") - def dict(self, handler): + def serialize_model(self, handler): res = handler(self) if res.get('metric_name') is None: res.pop('aggregation') diff --git a/libs/labelbox/src/labelbox/data/annotation_types/types.py b/libs/labelbox/src/labelbox/data/annotation_types/types.py index c1dd78680..b26789aae 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/types.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/types.py @@ -23,16 +23,6 @@ def __get_validators__(cls): def validate(cls, val, field: Field): if not isinstance(val, np.ndarray): raise TypeError(f"Expected numpy array. Found {type(val)}") - - if sys.version_info.minor > 6: - actual_dtype = field.sub_fields[-1].type_.__args__[0] - else: - actual_dtype = field.sub_fields[-1].type_.__values__[0] - - if val.dtype != actual_dtype: - raise TypeError( - f"Expected numpy array have type {actual_dtype}. Found {val.dtype}" - ) return val diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index 41ea3491b..e82aa89fa 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -7,7 +7,8 @@ from labelbox.data.annotation_types.feature import FeatureSchema from labelbox.data.mixins import ConfidenceNotSupportedMixin, CustomMetricsNotSupportedMixin from labelbox.utils import _CamelCaseMixin, is_valid_uri -from pydantic import model_validator, BaseModel, field_validator +from pydantic import model_validator, BaseModel, field_validator, model_serializer, Field, ConfigDict, AliasChoices +from labelbox.pydantic_serializers import _feature_serializer class VideoClassificationAnnotation(ClassificationAnnotation): @@ -15,7 +16,7 @@ class VideoClassificationAnnotation(ClassificationAnnotation): Args: name (Optional[str]) feature_schema_id (Optional[Cuid]) - value (Union[Text, Checklist, Radio, Dropdown]) + value (Union[Text, Checklist, Radio]) frame (int): The frame index that this annotation corresponds to segment_id (Optional[Int]): Index of video segment this annotation belongs to extra (Dict[str, Any]) @@ -89,14 +90,15 @@ class DICOMObjectAnnotation(VideoObjectAnnotation): class MaskFrame(_CamelCaseMixin, BaseModel): index: int - instance_uri: Optional[str] = None + instance_uri: Optional[str] = Field(default=None, validation_alias=AliasChoices("instanceURI", "instanceUri"), serialization_alias="instanceURI") im_bytes: Optional[bytes] = None + + model_config = ConfigDict(populate_by_name=True) @model_validator(mode="after") def validate_args(cls, values): im_bytes = values.im_bytes instance_uri = values.instance_uri - if im_bytes == instance_uri == None: raise ValueError("One of `instance_uri`, `im_bytes` required.") return values @@ -109,9 +111,10 @@ def validate_uri(cls, v): class MaskInstance(_CamelCaseMixin, FeatureSchema): - color_rgb: Tuple[int, int, int] + color_rgb: Tuple[int, int, int] = Field(validation_alias=AliasChoices("colorRGB", "colorRgb"), serialization_alias="colorRGB") name: str + model_config = ConfigDict(populate_by_name=True) class VideoMaskAnnotation(BaseModel): """Video mask annotation diff --git a/libs/labelbox/src/labelbox/data/mixins.py b/libs/labelbox/src/labelbox/data/mixins.py index e95cec3f4..de6a8c247 100644 --- a/libs/labelbox/src/labelbox/data/mixins.py +++ b/libs/labelbox/src/labelbox/data/mixins.py @@ -58,12 +58,6 @@ class CustomMetricsMixin(BaseModel): @model_serializer(mode="wrap") def serialize_model(self, handler): res = handler(self) - if "customMetrics" in res and res["customMetrics"] is None: - res.pop("customMetrics") - - if "custom_metrics" in res and res["custom_metrics"] is None: - res.pop("custom_metrics") - return res diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/converter.py b/libs/labelbox/src/labelbox/data/serialization/coco/converter.py index e222fb01c..1f6e8b178 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/converter.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/converter.py @@ -65,7 +65,7 @@ def serialize_instances(labels: LabelCollection, image_root = create_path_if_not_exists(image_root, ignore_existing_data) return CocoInstanceDataset.from_common(labels=labels, image_root=image_root, - max_workers=max_workers).dict() + max_workers=max_workers).model_dump() @staticmethod def serialize_panoptic(labels: LabelCollection, @@ -104,7 +104,7 @@ def serialize_panoptic(labels: LabelCollection, image_root=image_root, mask_root=mask_root, all_stuff=all_stuff, - max_workers=max_workers).dict() + max_workers=max_workers).model_dump() @staticmethod def deserialize_panoptic(json_data: Dict[str, Any], image_root: Union[Path, diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py index 06b9c6200..c87a04f14 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/classification.py @@ -3,7 +3,7 @@ from .feature import LBV1Feature from ...annotation_types.annotation import ClassificationAnnotation -from ...annotation_types.classification import Checklist, ClassificationAnswer, Radio, Text, Dropdown +from ...annotation_types.classification import Checklist, ClassificationAnswer, Radio, Text from ...annotation_types.types import Cuid from pydantic import BaseModel @@ -61,23 +61,6 @@ def from_common(cls, checklist: Checklist, feature_schema_id: Cuid, **extra) -class LBV1Dropdown(LBV1Feature): - answer: List[LBV1ClassificationAnswer] - - def to_common(self) -> Dropdown: - return Dropdown(answer=[answer.to_common() for answer in self.answer]) - - @classmethod - def from_common(cls, dropdown: Dropdown, feature_schema_id: Cuid, - **extra) -> "LBV1Dropdown": - return cls(schema_id=feature_schema_id, - answer=[ - LBV1ClassificationAnswer.from_common(answer) - for answer in dropdown.answer - ], - **extra) - - class LBV1Text(LBV1Feature): answer: str @@ -91,7 +74,7 @@ def from_common(cls, text: Text, feature_schema_id: Cuid, class LBV1Classifications(BaseModel): - classifications: List[Union[LBV1Text, LBV1Radio, LBV1Dropdown, + classifications: List[Union[LBV1Text, LBV1Radio, LBV1Checklist]] = [] def to_common(self) -> List[ClassificationAnnotation]: @@ -129,7 +112,6 @@ def lookup_classification( ) -> Union[LBV1Text, LBV1Checklist, LBV1Radio, LBV1Checklist]: return { Text: LBV1Text, - Dropdown: LBV1Dropdown, Checklist: LBV1Checklist, Radio: LBV1Radio }.get(type(annotation.value)) diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/converter.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/converter.py index 17595b5e7..570a63aa4 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/converter.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/converter.py @@ -75,7 +75,7 @@ def serialize( """ for label in labels: res = LBV1Label.from_common(label) - yield res.dict(by_alias=True) + yield res.model_dump(by_alias=True) class LBV1VideoIterator(PrefetchGenerator): diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py index b150db71a..7dc18501d 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py @@ -31,7 +31,7 @@ def from_common( [x for x in annotations if isinstance(x, ObjectAnnotation)]) classifications = LBV1Classifications.from_common( [x for x in annotations if isinstance(x, ClassificationAnnotation)]) - return cls(**objects.dict(), **classifications.dict()) + return cls(**objects.model_dump(), **classifications.model_dump()) class LBV1LabelAnnotationsVideo(LBV1LabelAnnotations): @@ -119,7 +119,7 @@ class LBV1Label(BaseModel): List[LBV1LabelAnnotationsVideo]] = Field( ..., alias='Label') data_row_id: str = Field(..., alias="DataRow ID") - row_data: str = Field(None, alias="Labeled Data") + row_data: Optional[str] = Field(None, alias="Labeled Data") id: Optional[str] = Field(None, alias='ID') external_id: Optional[str] = Field(None, alias="External ID") data_row_media_attributes: Optional[Dict[str, Any]] = Field( diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py index 08b4ed2ee..44f9d913b 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py @@ -6,7 +6,7 @@ import numpy as np -from .classification import LBV1Checklist, LBV1Classifications, LBV1Radio, LBV1Text, LBV1Dropdown +from .classification import LBV1Checklist, LBV1Classifications, LBV1Radio, LBV1Text from .feature import LBV1Feature from ...annotation_types.annotation import (ClassificationAnnotation, ObjectAnnotation) @@ -14,13 +14,13 @@ from ...annotation_types.geometry import Line, Mask, Point, Polygon, Rectangle from ...annotation_types.ner import TextEntity from ...annotation_types.types import Cuid -from pydantic import BaseModel, Field, model_serializer, field_serializer +from pydantic import BaseModel, Field, model_serializer, field_validator class LBV1ObjectBase(LBV1Feature): color: Optional[str] = None instanceURI: Optional[str] = None - classifications: List[Union[LBV1Text, LBV1Radio, LBV1Dropdown, + classifications: List[Union[LBV1Text, LBV1Radio, LBV1Checklist]] = [] page: Optional[int] = None unit: Optional[str] = None @@ -33,7 +33,7 @@ def serialize_model(self, handler): res.pop('instanceURI') return res - @field_serializer('classifications', mode="before") + @field_validator('classifications', mode="before") def validate_subclasses(cls, value): # checklist subclasses create extra unessesary nesting. So we just remove it. if isinstance(value, list) and len(value): diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index db796c34c..2c26727f8 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -3,12 +3,24 @@ from labelbox.utils import _CamelCaseMixin, is_exactly_one_set from ...annotation_types.types import Cuid -from pydantic import field_validator, model_validator, model_serializer +from pydantic import field_validator, model_validator, model_serializer, ConfigDict, BaseModel, Field +from uuid import UUID, uuid4 +subclass_registry = {} + +class SubclassRegistryBase(BaseModel): + + model_config = ConfigDict(extra="allow") + + def __init_subclass__(cls, **kwargs): + super().__init_subclass__(**kwargs) + if cls.__name__ != "NDAnnotation": + subclass_registry[cls.__name__] = cls class DataRow(_CamelCaseMixin): - id: str = None - global_key: str = None + id: Optional[str] = None + global_key: Optional[str] = None + @model_validator(mode="after") def must_set_one(cls, values): @@ -18,22 +30,9 @@ def must_set_one(cls, values): class NDJsonBase(_CamelCaseMixin): - uuid: str = None + uuid: Optional[str] = Field(default_factory=lambda: str(uuid4())) data_row: DataRow - @field_validator('uuid', mode="before") - def set_id(cls, v): - return v or str(uuid4()) - - def dict(self, *args, **kwargs): - """ Pop missing id or missing globalKey from dataRow """ - res = super().model_dump(*args, **kwargs) - if not self.data_row.id: - res['dataRow'].pop('id') - if not self.data_row.global_key: - res['dataRow'].pop('globalKey') - return res - class NDAnnotation(NDJsonBase): name: Optional[str] = None diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index 0cb0e9cf9..d257d5ab0 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -6,17 +6,18 @@ from ...annotation_types.annotation import ClassificationAnnotation from ...annotation_types.video import VideoClassificationAnnotation from ...annotation_types.llm_prompt_response.prompt import PromptClassificationAnnotation, PromptText -from ...annotation_types.classification.classification import ClassificationAnswer, Dropdown, Text, Checklist, Radio +from ...annotation_types.classification.classification import ClassificationAnswer, Text, Checklist, Radio from ...annotation_types.types import Cuid from ...annotation_types.data import TextData, VideoData, ImageData from pydantic import model_validator, Field, BaseModel, ConfigDict, model_serializer from pydantic.alias_generators import to_camel +from .base import SubclassRegistryBase class NDAnswer(ConfidenceMixin, CustomMetricsMixin): name: Optional[str] = None schema_id: Optional[Cuid] = None - classifications: Optional[List['NDSubclassificationType']] = [] + classifications: Optional[List['NDSubclassificationType']] = None model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) @model_validator(mode="after") @@ -32,11 +33,9 @@ def serialize_model(self, handler): res.pop('name') if 'schemaId' in res and res['schemaId'] is None: res.pop('schemaId') - if self.classifications is None or len(self.classifications) == 0: - res.pop('classifications') - else: + if self.classifications: res['classifications'] = [ - c.model_dump() for c in self.classifications + c.model_dump(exclude_none=True) for c in self.classifications ] return res @@ -80,7 +79,7 @@ def from_common(cls, text: Text, name: str, class NDChecklistSubclass(NDAnswer): - answer: List[NDAnswer] = Field(..., alias='answers') + answer: List[NDAnswer] = Field(..., validation_alias='answers') def to_common(self) -> Checklist: @@ -91,7 +90,7 @@ def to_common(self) -> Checklist: classifications=[ NDSubclassification.to_common(annot) for annot in answer.classifications - ], + ] if answer.classifications else None, custom_metrics=answer.custom_metrics) for answer in self.answer ]) @@ -103,10 +102,7 @@ def from_common(cls, checklist: Checklist, name: str, NDAnswer(name=answer.name, schema_id=answer.feature_schema_id, confidence=answer.confidence, - classifications=[ - NDSubclassification.from_common(annot) - for annot in answer.classifications - ], + classifications=[NDSubclassification.from_common(annot) for annot in answer.classifications] if answer.classifications else None, custom_metrics=answer.custom_metrics) for answer in checklist.answer ], @@ -114,10 +110,11 @@ def from_common(cls, checklist: Checklist, name: str, schema_id=feature_schema_id) @model_serializer(mode="wrap") - def dict(self, handler): + def serialize_model(self, handler): res = handler(self) if 'answers' in res: - res['answer'] = res.pop('answers') + res['answer'] = res['answers'] + del res["answers"] return res @@ -132,7 +129,7 @@ def to_common(self) -> Radio: classifications=[ NDSubclassification.to_common(annot) for annot in self.answer.classifications - ], + ] if self.answer.classifications else None, custom_metrics=self.answer.custom_metrics)) @classmethod @@ -144,7 +141,7 @@ def from_common(cls, radio: Radio, name: str, classifications=[ NDSubclassification.from_common(annot) for annot in radio.answer.classifications - ], + ] if radio.answer.classifications else None, custom_metrics=radio.answer.custom_metrics), name=name, schema_id=feature_schema_id) @@ -173,7 +170,7 @@ def from_common(cls, prompt_text: PromptText, name: str, # ====== End of subclasses -class NDText(NDAnnotation, NDTextSubclass): +class NDText(NDAnnotation, NDTextSubclass, SubclassRegistryBase): @classmethod def from_common(cls, @@ -197,7 +194,14 @@ def from_common(cls, ) -class NDChecklist(NDAnnotation, NDChecklistSubclass, VideoSupported): +class NDChecklist(NDAnnotation, NDChecklistSubclass, VideoSupported, SubclassRegistryBase): + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) + if "classifications" in res and res["classifications"] == []: + del res["classifications"] + return res @classmethod def from_common( @@ -220,7 +224,7 @@ def from_common( classifications=[ NDSubclassification.from_common(annot) for annot in answer.classifications - ], + ] if answer.classifications else None, custom_metrics=answer.custom_metrics) for answer in checklist.answer ], @@ -233,7 +237,7 @@ def from_common( confidence=confidence) -class NDRadio(NDAnnotation, NDRadioSubclass, VideoSupported): +class NDRadio(NDAnnotation, NDRadioSubclass, VideoSupported, SubclassRegistryBase): @classmethod def from_common( @@ -253,7 +257,7 @@ def from_common( classifications=[ NDSubclassification.from_common(annot) for annot in radio.answer.classifications - ], + ] if radio.answer.classifications else None, custom_metrics=radio.answer.custom_metrics), data_row=DataRow(id=data.uid, global_key=data.global_key), name=name, @@ -263,8 +267,15 @@ def from_common( message_id=message_id, confidence=confidence) + @model_serializer(mode="wrap") + def serialize_model(self, handler): + res = handler(self) + if "classifications" in res and res["classifications"] == []: + del res["classifications"] + return res + -class NDPromptText(NDAnnotation, NDPromptTextSubclass): +class NDPromptText(NDAnnotation, NDPromptTextSubclass, SubclassRegistryBase): @classmethod def from_common( @@ -311,8 +322,6 @@ def to_common( def lookup_subclassification( annotation: ClassificationAnnotation ) -> Union[NDTextSubclass, NDChecklistSubclass, NDRadioSubclass]: - if isinstance(annotation.value, Dropdown): - raise TypeError("Dropdowns are not supported for MAL.") return { Text: NDTextSubclass, Checklist: NDChecklistSubclass, @@ -341,7 +350,7 @@ def to_common( for frame in annotation.frames: for idx in range(frame.start, frame.end + 1, 1): results.append( - VideoClassificationAnnotation(frame=idx, **common.dict())) + VideoClassificationAnnotation(frame=idx, **common.model_dump(exclude_none=True))) return results @classmethod @@ -367,8 +376,6 @@ def lookup_classification( annotation: Union[ClassificationAnnotation, VideoClassificationAnnotation] ) -> Union[NDText, NDChecklist, NDRadio]: - if isinstance(annotation.value, Dropdown): - raise TypeError("Dropdowns are not supported for MAL.") return { Text: NDText, Checklist: NDChecklist, diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py index 2ffeb9727..1046f82e9 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py @@ -15,6 +15,7 @@ from ...annotation_types.collection import LabelCollection, LabelGenerator from ...annotation_types.relationship import RelationshipAnnotation from .label import NDLabel +import copy logger = logging.getLogger(__name__) @@ -33,7 +34,8 @@ def deserialize(json_data: Iterable[Dict[str, Any]]) -> LabelGenerator: Returns: LabelGenerator containing the ndjson data. """ - data = NDLabel(**{"annotations": json_data}) + data = copy.copy(json_data) + data = NDLabel(**{"annotations": data}) res = data.to_common() return res @@ -72,7 +74,7 @@ def serialize( ConfusionMatrixMetric, RelationshipAnnotation, ]] = [] - # First pass to get all RelatiohnshipAnnotaitons + # First pass to get all RelationshipAnnotations # and update the UUIDs of the source and target annotations for annotation in label.annotations: if isinstance(annotation, RelationshipAnnotation): @@ -106,10 +108,10 @@ def serialize( if not isinstance(annotation, RelationshipAnnotation): uuid_safe_annotations.append(annotation) label.annotations = uuid_safe_annotations - for annotation in NDLabel.from_common([label]): - annotation_uuid = getattr(annotation, "uuid", None) - - res = annotation.dict( + for example in NDLabel.from_common([label]): + annotation_uuid = getattr(example, "uuid", None) + res = example.model_dump( + exclude_none=True, by_alias=True, exclude={"uuid"} if annotation_uuid == "None" else None, ) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index a9e94ba44..ddfa1c836 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -2,6 +2,7 @@ from operator import itemgetter from typing import Dict, Generator, List, Tuple, Union from collections import defaultdict +from typing_extensions import Unpack import warnings @@ -14,7 +15,6 @@ from ...annotation_types.data.generic_data_row_data import GenericDataRowData from ...annotation_types.label import Label from ...annotation_types.ner import TextEntity, ConversationEntity -from ...annotation_types.classification import Dropdown from ...annotation_types.metrics import ScalarMetric, ConfusionMatrixMetric from ...annotation_types.llm_prompt_response.prompt import PromptClassificationAnnotation @@ -23,7 +23,12 @@ from .objects import NDObject, NDObjectType, NDSegments, NDDicomSegments, NDVideoMasks, NDDicomMasks from .relationship import NDRelationship from .base import DataRow -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict, model_serializer, ValidationError +from labelbox.pydantic_serializers import _feature_serializer +from .base import subclass_registry, SubclassRegistryBase, NDAnnotation +from pydantic_core import PydanticUndefined +from pydantic.alias_generators import to_camel +from contextlib import suppress AnnotationType = Union[NDObjectType, NDClassificationType, NDPromptClassificationType, NDConfusionMatrixMetric, NDScalarMetric, NDDicomSegments, @@ -32,7 +37,42 @@ class NDLabel(BaseModel): - annotations: List[AnnotationType] + annotations: List[SubclassRegistryBase] + + def __init__(self, **kwargs): + for index in range(len(kwargs["annotations"])): + annotation = kwargs["annotations"][index] + if isinstance(annotation, dict): + item_annotation_keys = annotation.keys() + key_subclass_combos = defaultdict(list) + for name, subclass in subclass_registry.items(): + subclass: BaseModel = subclass + + # NDJSON has all required keys for a subclass. Serialize to first subclass. + annotation_keys = [] + for k, field in subclass.model_fields.items(): + # must account for alias + if hasattr(field, "validation_alias") and field.validation_alias == "answers" and "answers" in item_annotation_keys: + annotation_keys.append("answers") + elif field.default == PydanticUndefined and k != "uuid": + annotation_keys.append(to_camel(k)) + key_subclass_combos[subclass].extend(annotation_keys) + + # Sort by subclass that has the most keys + key_subclass_combos = dict(sorted(key_subclass_combos.items(), key = lambda x : len(x[1]), reverse=True)) + for subclass, key_subclass_combo in key_subclass_combos.items(): + check_required_keys = all(key in list(item_annotation_keys) for key in key_subclass_combo) + if check_required_keys: + # Keep trying subclasses until we find one that has valid values + with suppress(ValidationError): + annotation = subclass(**annotation) + break + kwargs["annotations"][index] = annotation + super().__init__(**kwargs) + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + return _feature_serializer(handler(self)) class _Relationship(BaseModel): """This object holds information about the relationship""" @@ -263,11 +303,6 @@ def _create_non_video_annotations(cls, label: Label): ] for annotation in non_video_annotations: if isinstance(annotation, ClassificationAnnotation): - if isinstance(annotation.value, Dropdown): - raise ValueError( - "Dropdowns are not supported by the NDJson format." - " Please filter out Dropdown annotations before converting." - ) yield NDClassification.from_common(annotation, label.data) elif isinstance(annotation, ObjectAnnotation): yield NDObject.from_common(annotation, label.data) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py index 45a7ded14..16f426dc4 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py @@ -9,6 +9,7 @@ ConfusionMatrixAggregation, ConfusionMatrixMetric, ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue) from pydantic import ConfigDict, model_serializer +from .base import SubclassRegistryBase class BaseNDMetric(NDJsonBase): @@ -21,12 +22,12 @@ class BaseNDMetric(NDJsonBase): def serialize_model(self, handler): res = handler(self) for field in ['featureName', 'subclassName']: - if res[field] is None: + if field in res and res[field] is None: res.pop(field) return res -class NDConfusionMatrixMetric(BaseNDMetric): +class NDConfusionMatrixMetric(BaseNDMetric, SubclassRegistryBase): metric_value: Union[ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue] metric_name: str @@ -53,10 +54,10 @@ def from_common( data_row=DataRow(id=data.uid, global_key=data.global_key)) -class NDScalarMetric(BaseNDMetric): +class NDScalarMetric(BaseNDMetric, SubclassRegistryBase): metric_value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] - metric_name: Optional[str] - aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN + metric_name: Optional[str] = None + aggregation: Optional[ScalarMetricAggregation] = ScalarMetricAggregation.ARITHMETIC_MEAN def to_common(self) -> ScalarMetric: return ScalarMetric(value=self.metric_value, @@ -77,15 +78,6 @@ def from_common(cls, metric: ScalarMetric, aggregation=metric.aggregation.value, data_row=DataRow(id=data.uid, global_key=data.global_key)) - @model_serializer(mode = "wrap") - def serialize_model(self, handler): - res = handler(self) - # For backwards compatibility. - if res['metricName'] is None: - res.pop('metricName') - res.pop('aggregation') - return res - class NDMetricAnnotation: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index d07499f99..c79e45e6c 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -19,7 +19,7 @@ from ...annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation from ...annotation_types.video import VideoMaskAnnotation, DICOMMaskAnnotation, MaskFrame, MaskInstance from .classification import NDClassification, NDSubclassification, NDSubclassificationType -from .base import DataRow, NDAnnotation, NDJsonBase +from .base import DataRow, NDAnnotation, NDJsonBase, SubclassRegistryBase from pydantic import BaseModel @@ -48,7 +48,7 @@ class Bbox(BaseModel): width: float -class NDPoint(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDPoint(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): point: _Point def to_common(self) -> Point: @@ -79,7 +79,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFramePoint(VideoSupported): +class NDFramePoint(VideoSupported, SubclassRegistryBase): point: _Point classifications: List[NDSubclassificationType] = [] @@ -109,7 +109,7 @@ def from_common( classifications=classifications) -class NDLine(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDLine(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): line: List[_Point] def to_common(self) -> Line: @@ -140,7 +140,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFrameLine(VideoSupported): +class NDFrameLine(VideoSupported, SubclassRegistryBase): line: List[_Point] classifications: List[NDSubclassificationType] = [] @@ -173,7 +173,7 @@ def from_common( classifications=classifications) -class NDDicomLine(NDFrameLine): +class NDDicomLine(NDFrameLine, SubclassRegistryBase): def to_common(self, name: str, feature_schema_id: Cuid, segment_index: int, group_key: str) -> DICOMObjectAnnotation: @@ -187,7 +187,7 @@ def to_common(self, name: str, feature_schema_id: Cuid, segment_index: int, group_key=group_key) -class NDPolygon(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDPolygon(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): polygon: List[_Point] def to_common(self) -> Polygon: @@ -218,7 +218,7 @@ def from_common( custom_metrics=custom_metrics) -class NDRectangle(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDRectangle(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): bbox: Bbox def to_common(self) -> Rectangle: @@ -254,7 +254,7 @@ def from_common( custom_metrics=custom_metrics) -class NDDocumentRectangle(NDRectangle): +class NDDocumentRectangle(NDRectangle, SubclassRegistryBase): page: int unit: str @@ -293,7 +293,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFrameRectangle(VideoSupported): +class NDFrameRectangle(VideoSupported, SubclassRegistryBase): bbox: Bbox classifications: List[NDSubclassificationType] = [] @@ -398,7 +398,7 @@ def to_common(self, name: str, feature_schema_id: Cuid, uuid: str, ] -class NDSegments(NDBaseObject): +class NDSegments(NDBaseObject, SubclassRegistryBase): segments: List[NDSegment] def to_common(self, name: str, feature_schema_id: Cuid): @@ -425,7 +425,7 @@ def from_common(cls, segments: List[VideoObjectAnnotation], data: VideoData, uuid=extra.get('uuid')) -class NDDicomSegments(NDBaseObject, DicomSupported): +class NDDicomSegments(NDBaseObject, DicomSupported, SubclassRegistryBase): segments: List[NDDicomSegment] def to_common(self, name: str, feature_schema_id: Cuid): @@ -463,7 +463,7 @@ class _PNGMask(BaseModel): png: str -class NDMask(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDMask(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): mask: Union[_URIMask, _PNGMask] def to_common(self) -> Mask: @@ -517,7 +517,7 @@ class NDVideoMasksFramesInstances(BaseModel): instances: List[MaskInstance] -class NDVideoMasks(NDJsonBase, ConfidenceMixin, CustomMetricsNotSupportedMixin): +class NDVideoMasks(NDJsonBase, ConfidenceMixin, CustomMetricsNotSupportedMixin, SubclassRegistryBase): masks: NDVideoMasksFramesInstances def to_common(self) -> VideoMaskAnnotation: @@ -545,7 +545,7 @@ def from_common(cls, annotation, data): ) -class NDDicomMasks(NDVideoMasks, DicomSupported): +class NDDicomMasks(NDVideoMasks, DicomSupported, SubclassRegistryBase): def to_common(self) -> DICOMMaskAnnotation: return DICOMMaskAnnotation( @@ -569,7 +569,7 @@ class Location(BaseModel): end: int -class NDTextEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDTextEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): location: Location def to_common(self) -> TextEntity: @@ -601,7 +601,7 @@ def from_common( custom_metrics=custom_metrics) -class NDDocumentEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin): +class NDDocumentEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): name: str text_selections: List[DocumentTextSelection] @@ -633,7 +633,7 @@ def from_common( custom_metrics=custom_metrics) -class NDConversationEntity(NDTextEntity): +class NDConversationEntity(NDTextEntity, SubclassRegistryBase): message_id: str def to_common(self) -> ConversationEntity: @@ -715,7 +715,7 @@ def from_common( if isinstance(first_video_annotation, DICOMObjectAnnotation): group_key = first_video_annotation.group_key.value args.update(dict(group_key=group_key)) - + return obj.from_common(**args) elif (obj == NDVideoMasks or obj == NDDicomMasks): return obj.from_common(annotation, data) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py index d95c1584f..e3e49ad5d 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py @@ -5,7 +5,7 @@ from ...annotation_types.relationship import RelationshipAnnotation from ...annotation_types.relationship import Relationship from .objects import NDObjectType -from .base import DataRow +from .base import DataRow, SubclassRegistryBase SUPPORTED_ANNOTATIONS = NDObjectType @@ -16,7 +16,7 @@ class _Relationship(BaseModel): type: str -class NDRelationship(NDAnnotation): +class NDRelationship(NDAnnotation, SubclassRegistryBase): relationship: _Relationship @staticmethod diff --git a/libs/labelbox/src/labelbox/pydantic_serializers.py b/libs/labelbox/src/labelbox/pydantic_serializers.py index 743a418ac..8f2e94ff7 100644 --- a/libs/labelbox/src/labelbox/pydantic_serializers.py +++ b/libs/labelbox/src/labelbox/pydantic_serializers.py @@ -1,21 +1,31 @@ from typing import Dict -def _feature_serializer(res: Dict) -> Dict: - """Used as a with custom model serializer for pydantics. This ensures backwards compatibility since pydantic V1 allowed you to override Dict method. This method needs to be used for all base classes and sub classes. We should look at getting this removed.""" - if "customMetrics" in res and res["customMetrics"] is None: - res.pop("customMetrics") - if "custom_metrics" in res and res["custom_metrics"] is None: - res.pop("custom_metrics") - if "keyframe" in res and res["keyframe"] == None: - res.pop("keyframe") - if "classifications" in res and res["classifications"] == []: - res.pop("classifications") - if "confidence" in res and res["confidence"] is None: - res.pop("confidence") - if 'name' in res and res['name'] is None: - res.pop('name') - if 'featureSchemaId' in res and res['featureSchemaId'] is None: - res.pop('featureSchemaId') + +def _check_keys(key: str) -> bool: + if "customMetrics" == key: + return True + if "custom_metrics" == key: + return True + if "keyframe" == key: + return True + if "classifications" == key: + return True + if "confidence" == key: + return True + if "name" == key: + return True + if 'featureSchemaId' == key: + return True + if "schemaId" == key: + return True + return False +def _feature_serializer(res: Dict) -> Dict: + """Used with custom model serializer for Pydantics. This ensures backwards compatibility since Pydantic V1 allowed you to override dict/model_dump method that worked with nested models. This method needs to be used for all base classes and sub classes for same behavior with a model_serializer decorator. We should look at getting this removed by allowing our API to accept null values for fields that are optional.""" + for k, v in res.items(): + if _check_keys(k) and v == None: + del res[k] + if isinstance(res[k], Dict): + _feature_serializer(v) return res \ No newline at end of file diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index 919edc9ec..68fe6cc2a 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -513,7 +513,7 @@ def get_mal_schemas(ontology): return valid_feature_schemas_by_schema_id, valid_feature_schemas_by_name -LabelboxID: str = Annotated[str, StringConstraints(min_length=25, max_length=25)] +LabelboxID: Type[str] = Annotated[str, StringConstraints(min_length=25, max_length=25)] class Bbox(BaseModel): @@ -535,7 +535,7 @@ class FrameLocation(BaseModel): class VideoSupported(BaseModel): #Note that frames are only allowed as top level inferences for video - frames: Optional[List[FrameLocation]] + frames: Optional[List[FrameLocation]] = None # Base class for a special kind of union. @@ -825,7 +825,7 @@ class NDTextEntity(NDBaseTool): @field_validator('location') def is_valid_location(cls, v): if isinstance(v, BaseModel): - v = v.dict() + v = v.model_dump() if len(v) < 2: raise ValueError( diff --git a/libs/labelbox/src/labelbox/schema/consensus_settings.py b/libs/labelbox/src/labelbox/schema/consensus_settings.py index e94c4b63f..001d51301 100644 --- a/libs/labelbox/src/labelbox/schema/consensus_settings.py +++ b/libs/labelbox/src/labelbox/schema/consensus_settings.py @@ -15,5 +15,5 @@ class ConsensusSettings(_CamelCaseMixin): coverage_percentage: Percentage of data rows to be labeled more than once """ - number_of_labels: int = Field(validation_alias=AliasChoices("numberOfLabels", "number_of_labels")) - coverage_percentage: float = Field(validation_alias=AliasChoices("coveragePercentage", "coverage_percentage")) + number_of_labels: int + coverage_percentage: float diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index d4dca504a..0a0b25ff2 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -47,11 +47,11 @@ class DataRowMetadataSchema(BaseModel): # Metadata base class -class DataRowMetadataField(BaseModel): +class DataRowMetadataField(_CamelCaseMixin): # One of `schema_id` or `name` must be provided. If `schema_id` is not provided, it is # inferred from `name` # schema id alias to json key name for pydantic v2 support - schema_id: Optional[SchemaId] = Field(default=None, serialization_alias="schemaId") + schema_id: Optional[SchemaId] = None name: Optional[str] = None # value is of type `Any` so that we do not improperly coerce the value to the wrong type # Additional validation is performed before upload using the schema information @@ -59,15 +59,14 @@ class DataRowMetadataField(BaseModel): class DataRowMetadata(_CamelCaseMixin): - global_key: Optional[str] = Field(default=None, validation_alias=AliasChoices("global_key", "globalKey")) - data_row_id: Optional[str] = Field(default=None, validation_alias=AliasChoices("data_row_id", "dataRowId")) + global_key: Optional[str] = None + data_row_id: Optional[str] = None fields: List[DataRowMetadataField] class DeleteDataRowMetadata(_CamelCaseMixin): - data_row_id: Union[str, UniqueId, GlobalKey] = Field(validation_alias=AliasChoices("data_row_id", "dataRowId")) + data_row_id: Union[str, UniqueId, GlobalKey] = None fields: List[SchemaId] - model_config = ConfigDict(arbitrary_types_allowed = True) class DataRowMetadataBatchResponse(_CamelCaseMixin): @@ -89,15 +88,14 @@ class _UpsertDataRowMetadataInput(_CamelCaseMixin): # Batch of upsert values for a datarow class _UpsertBatchDataRowMetadata(_CamelCaseMixin): - global_key: Optional[str] = Field(default=None, validation_alias=AliasChoices("global_key", "globalKey")) - data_row_id: Optional[str] = Field(default=None, validation_alias=AliasChoices("data_row_id", "dataRowId")) + global_key: Optional[str] = None + data_row_id: Optional[str] = None fields: List[_UpsertDataRowMetadataInput] class _DeleteBatchDataRowMetadata(_CamelCaseMixin): data_row_identifier: Union[UniqueId, GlobalKey] schema_ids: List[SchemaId] - model_config = ConfigDict(arbitrary_types_allowed=True, alias_generator=AliasGenerator(serialization_alias=to_camel)) @model_serializer(mode="wrap") def serialize_model(self, handler): diff --git a/libs/labelbox/src/labelbox/schema/export_task.py b/libs/labelbox/src/labelbox/schema/export_task.py index 66c1b66d8..423e66ceb 100644 --- a/libs/labelbox/src/labelbox/schema/export_task.py +++ b/libs/labelbox/src/labelbox/schema/export_task.py @@ -49,8 +49,8 @@ class Range(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-metho class _MetadataHeader(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods - total_size: int = Field(validation_alias=AliasChoices("total_size", "totalSize")) - total_lines: int = Field(validation_alias=AliasChoices("total_lines", "totalLines")) + total_size: int + total_lines: int class _MetadataFileInfo(_CamelCaseMixin, BaseModel): # pylint: disable=too-few-public-methods diff --git a/libs/labelbox/src/labelbox/schema/foundry/app.py b/libs/labelbox/src/labelbox/schema/foundry/app.py index 7441117ac..52743e55b 100644 --- a/libs/labelbox/src/labelbox/schema/foundry/app.py +++ b/libs/labelbox/src/labelbox/schema/foundry/app.py @@ -1,10 +1,11 @@ -from labelbox.utils import _CamelCaseMixin from typing import Any, Dict, Optional -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict, AliasGenerator +from pydantic.alias_generators import to_camel, to_snake +from labelbox.utils import _CamelCaseMixin -class App(_CamelCaseMixin, BaseModel): - id: Optional[str] +class App(_CamelCaseMixin): + id: Optional[str] = None model_id: str name: str description: Optional[str] = None diff --git a/libs/labelbox/src/labelbox/schema/foundry/foundry_client.py b/libs/labelbox/src/labelbox/schema/foundry/foundry_client.py index c184a2a81..27d577bc0 100644 --- a/libs/labelbox/src/labelbox/schema/foundry/foundry_client.py +++ b/libs/labelbox/src/labelbox/schema/foundry/foundry_client.py @@ -30,7 +30,7 @@ def _create_app(self, app: App) -> App: }} """ - params = app.dict(by_alias=True, exclude={"id"}) + params = app.model_dump(by_alias=True, exclude={"id"}) try: response = self.client.execute(query_str, params) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 34e258de1..7b74acdc2 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -93,12 +93,7 @@ def add_option(self, option: Union["Classification", "PromptResponseClassificati @dataclass class Classification: - """ - - Deprecation Notice: Dropdown classification is deprecated and will be - removed in a future release. Dropdown will also - no longer be able to be created in the Editor on 3/31/2022. - + """ A classification to be added to a Project's ontology. The classification is dependent on the Classification Type. @@ -136,7 +131,6 @@ class Type(Enum): TEXT = "text" CHECKLIST = "checklist" RADIO = "radio" - DROPDOWN = "dropdown" class Scope(Enum): GLOBAL = "global" @@ -146,7 +140,7 @@ class UIMode(Enum): HOTKEY = "hotkey" SEARCHABLE = "searchable" - _REQUIRES_OPTIONS = {Type.CHECKLIST, Type.RADIO, Type.DROPDOWN} + _REQUIRES_OPTIONS = {Type.CHECKLIST, Type.RADIO} class_type: Type name: Optional[str] = None @@ -159,12 +153,6 @@ class UIMode(Enum): ui_mode: Optional[UIMode] = None # How this classification should be answered (e.g. hotkeys / autocomplete, etc) def __post_init__(self): - if self.class_type == Classification.Type.DROPDOWN: - warnings.warn( - "Dropdown classification is deprecated and will be " - "removed in a future release. Dropdown will also " - "no longer be able to be created in the Editor on 3/31/2022.") - if self.name is None: msg = ( "When creating the Classification feature, please use “name” " diff --git a/libs/labelbox/src/labelbox/schema/project.py b/libs/labelbox/src/labelbox/schema/project.py index f8873215b..5d9458468 100644 --- a/libs/labelbox/src/labelbox/schema/project.py +++ b/libs/labelbox/src/labelbox/schema/project.py @@ -992,7 +992,7 @@ def create_batches( dr_ids, global_keys, self._wait_processing_max_seconds) if consensus_settings: - consensus_settings = ConsensusSettings(**consensus_settings).dict( + consensus_settings = ConsensusSettings(**consensus_settings).model_dump( by_alias=True) method = 'createBatches' @@ -1059,7 +1059,7 @@ def create_batches_from_dataset( raise ValueError("Project must be in batch mode") if consensus_settings: - consensus_settings = ConsensusSettings(**consensus_settings).dict( + consensus_settings = ConsensusSettings(**consensus_settings).model_dump( by_alias=True) method = 'createBatchesFromDataset' diff --git a/libs/labelbox/src/labelbox/utils.py b/libs/labelbox/src/labelbox/utils.py index b98011abe..21f0c338b 100644 --- a/libs/labelbox/src/labelbox/utils.py +++ b/libs/labelbox/src/labelbox/utils.py @@ -62,7 +62,7 @@ def is_valid_uri(uri): class _CamelCaseMixin(BaseModel): - model_config = ConfigDict(arbitrary_types_allowed = True, alias_generator = to_camel) + model_config = ConfigDict(arbitrary_types_allowed = True, alias_generator = to_camel, populate_by_name = True) class _NoCoercionMixin: diff --git a/libs/labelbox/tests/conftest.py b/libs/labelbox/tests/conftest.py index a69556c04..a14accf87 100644 --- a/libs/labelbox/tests/conftest.py +++ b/libs/labelbox/tests/conftest.py @@ -1053,9 +1053,6 @@ def configured_project_with_complex_ontology(client, initial_dataset, rand_gen, classifications = [ Classification(class_type=Classification.Type.TEXT, name="test-text-class"), - Classification(class_type=Classification.Type.DROPDOWN, - name="test-dropdown-class", - options=options), Classification(class_type=Classification.Type.RADIO, name="test-radio-class", options=options), diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index 24dc1b9b2..d173c314e 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -34,7 +34,7 @@ def test_legacy_scalar_metric(): 'uid': None, 'is_benchmark_reference': False } - assert label.dict() == expected + assert label.model_dump() == expected # TODO: Test with confidence @@ -97,7 +97,7 @@ def test_custom_scalar_metric(feature_name, subclass_name, aggregation, value): 'is_benchmark_reference': False } - assert label.dict() == expected + assert label.model_dump() == expected @pytest.mark.parametrize('feature_name,subclass_name,aggregation,value', [ @@ -154,7 +154,7 @@ def test_custom_confusison_matrix_metric(feature_name, subclass_name, 'uid': None, 'is_benchmark_reference': False } - assert label.dict() == expected + assert label.model_dump() == expected def test_name_exists(): diff --git a/libs/labelbox/tests/data/annotation_types/test_video.py b/libs/labelbox/tests/data/annotation_types/test_video.py index 0e3cd7ec4..39aca1073 100644 --- a/libs/labelbox/tests/data/annotation_types/test_video.py +++ b/libs/labelbox/tests/data/annotation_types/test_video.py @@ -4,7 +4,7 @@ def test_mask_frame(): mask_frame = lb_types.MaskFrame(index=1, instance_uri="http://path/to/frame.png") - assert mask_frame.dict(by_alias=True) == { + assert mask_frame.model_dump(by_alias=True) == { 'index': 1, 'imBytes': None, 'instanceURI': 'http://path/to/frame.png' @@ -13,7 +13,7 @@ def test_mask_frame(): def test_mask_instance(): mask_instance = lb_types.MaskInstance(color_rgb=(0, 0, 255), name="mask1") - assert mask_instance.dict(by_alias=True) == { + assert mask_instance.model_dump(by_alias=True) == { 'colorRGB': (0, 0, 255), 'name': 'mask1' } diff --git a/libs/labelbox/tests/data/assets/ndjson/classification_import_global_key.json b/libs/labelbox/tests/data/assets/ndjson/classification_import_global_key.json index 39116479a..4de15e217 100644 --- a/libs/labelbox/tests/data/assets/ndjson/classification_import_global_key.json +++ b/libs/labelbox/tests/data/assets/ndjson/classification_import_global_key.json @@ -14,7 +14,7 @@ } ] }, - "schemaId": "c123", + "schemaId": "ckrb1sfl8099g0y91cxbd5ftb", "dataRow": { "globalKey": "05e8ee85-072e-4eb2-b30a-501dee9b0d9d" }, @@ -51,4 +51,4 @@ }, "uuid": "ee70fd88-9f88-48dd-b760-7469ff479b71" } -] +] \ No newline at end of file diff --git a/libs/labelbox/tests/data/assets/ndjson/metric_import.json b/libs/labelbox/tests/data/assets/ndjson/metric_import.json index 2277cf758..ee98756f8 100644 --- a/libs/labelbox/tests/data/assets/ndjson/metric_import.json +++ b/libs/labelbox/tests/data/assets/ndjson/metric_import.json @@ -1 +1,10 @@ -[{"uuid" : "a22bbf6e-b2da-4abe-9a11-df84759f7672","dataRow" : {"id": "ckrmdnqj4000007msh9p2a27r"}, "metricValue" : 0.1}] +[ + { + "uuid": "a22bbf6e-b2da-4abe-9a11-df84759f7672", + "dataRow": { + "id": "ckrmdnqj4000007msh9p2a27r" + }, + "metricValue": 0.1, + "aggregation": "ARITHMETIC_MEAN" + } +] \ No newline at end of file diff --git a/libs/labelbox/tests/data/assets/ndjson/metric_import_global_key.json b/libs/labelbox/tests/data/assets/ndjson/metric_import_global_key.json index 666f4ec97..31be5a4c7 100644 --- a/libs/labelbox/tests/data/assets/ndjson/metric_import_global_key.json +++ b/libs/labelbox/tests/data/assets/ndjson/metric_import_global_key.json @@ -1 +1,10 @@ -[{"uuid" : "a22bbf6e-b2da-4abe-9a11-df84759f7672","dataRow" : {"globalKey": "05e8ee85-072e-4eb2-b30a-501dee9b0d9d"}, "metricValue" : 0.1}] +[ + { + "uuid": "a22bbf6e-b2da-4abe-9a11-df84759f7672", + "aggregation": "ARITHMETIC_MEAN", + "dataRow": { + "globalKey": "05e8ee85-072e-4eb2-b30a-501dee9b0d9d" + }, + "metricValue": 0.1 + } +] \ No newline at end of file diff --git a/libs/labelbox/tests/data/assets/ndjson/video_import.json b/libs/labelbox/tests/data/assets/ndjson/video_import.json index c7f214527..8199458cf 100644 --- a/libs/labelbox/tests/data/assets/ndjson/video_import.json +++ b/libs/labelbox/tests/data/assets/ndjson/video_import.json @@ -1,166 +1,210 @@ -[{ - "answer": { - "schemaId": "ckrb1sfl8099g0y91cxbd5ftb" - }, - "schemaId": "ckrb1sfjx099a0y914hl319ie", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", - "frames": [{ - "start": 30, - "end": 35 - }, { - "start": 50, - "end": 51 - }] -}, { - "answer": [{ - "schemaId": "ckrb1sfl8099e0y919v260awv" - }], - "schemaId": "ckrb1sfkn099c0y910wbo0p1a", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", - "frames": [{ - "start": 0, - "end": 5 - }] -}, { - "answer": "a value", - "schemaId": "ckrb1sfkn099c0y910wbo0p1a", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" +[ + { + "answer": { + "schemaId": "ckrb1sfl8099g0y91cxbd5ftb" + }, + "schemaId": "ckrb1sfjx099a0y914hl319ie", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", + "frames": [ + { + "start": 30, + "end": 35 + }, + { + "start": 50, + "end": 51 + } + ] }, - "uuid": "90e2ecf7-c19c-47e6-8cdb-8867e1b9d88c" -}, { - "classifications": [], - "schemaId": - "cl5islwg200gfci6g0oitaypu", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "answer": [ + { + "schemaId": "ckrb1sfl8099e0y919v260awv" + } + ], + "schemaId": "ckrb1sfkn099c0y910wbo0p1a", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", + "frames": [ + { + "start": 0, + "end": 5 + } + ] }, - "uuid": - "6f7c835a-0139-4896-b73f-66a6baa89e94", - "segments": [{ - "keyframes": [{ - "frame": 1, - "line": [{ - "x": 10.0, - "y": 10.0 - }, { - "x": 100.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }, { - "frame": 5, - "line": [{ - "x": 15.0, - "y": 10.0 - }, { - "x": 50.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 8, - "line": [{ - "x": 100.0, - "y": 10.0 - }, { - "x": 50.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }] - }] -}, { - "classifications": [], - "schemaId": - "cl5it7ktp00i5ci6gf80b1ysd", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "answer": "a value", + "schemaId": "ckrb1sfkn099c0y910wbo0p1a", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "90e2ecf7-c19c-47e6-8cdb-8867e1b9d88c" }, - "uuid": - "f963be22-227b-4efe-9be4-2738ed822216", - "segments": [{ - "keyframes": [{ - "frame": 1, - "point": { - "x": 10.0, - "y": 10.0 + { + "classifications": [], + "schemaId": "cl5islwg200gfci6g0oitaypu", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "6f7c835a-0139-4896-b73f-66a6baa89e94", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "line": [ + { + "x": 10.0, + "y": 10.0 + }, + { + "x": 100.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + }, + { + "frame": 5, + "line": [ + { + "x": 15.0, + "y": 10.0 + }, + { + "x": 50.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + } + ] }, - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 5, - "point": { - "x": 50.0, - "y": 50.0 - }, - "classifications": [] - }, { - "frame": 10, - "point": { - "x": 10.0, - "y": 50.0 - }, - "classifications": [] - }] - }] -}, { - "classifications": [], - "schemaId": - "cl5iw0roz00lwci6g5jni62vs", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "keyframes": [ + { + "frame": 8, + "line": [ + { + "x": 100.0, + "y": 10.0 + }, + { + "x": 50.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + } + ] + } + ] }, - "uuid": - "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", - "segments": [{ - "keyframes": [{ - "frame": 1, - "bbox": { - "top": 10.0, - "left": 5.0, - "height": 100.0, - "width": 150.0 + { + "classifications": [], + "schemaId": "cl5it7ktp00i5ci6gf80b1ysd", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "f963be22-227b-4efe-9be4-2738ed822216", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "point": { + "x": 10.0, + "y": 10.0 + }, + "classifications": [] + } + ] }, - "classifications": [] - }, { - "frame": 5, - "bbox": { - "top": 30.0, - "left": 5.0, - "height": 50.0, - "width": 150.0 - }, - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 10, - "bbox": { - "top": 300.0, - "left": 200.0, - "height": 400.0, - "width": 150.0 + { + "keyframes": [ + { + "frame": 5, + "point": { + "x": 50.0, + "y": 50.0 + }, + "classifications": [] + }, + { + "frame": 10, + "point": { + "x": 10.0, + "y": 50.0 + }, + "classifications": [] + } + ] + } + ] + }, + { + "classifications": [], + "schemaId": "cl5iw0roz00lwci6g5jni62vs", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "bbox": { + "top": 10.0, + "left": 5.0, + "height": 100.0, + "width": 150.0 + }, + "classifications": [] + }, + { + "frame": 5, + "bbox": { + "top": 30.0, + "left": 5.0, + "height": 50.0, + "width": 150.0 + }, + "classifications": [] + } + ] }, - "classifications": [] - }] - }] -}] + { + "keyframes": [ + { + "frame": 10, + "bbox": { + "top": 300.0, + "left": 200.0, + "height": 400.0, + "width": 150.0 + }, + "classifications": [] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json b/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json index 8c287aac2..1210b6059 100644 --- a/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json +++ b/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json @@ -1,166 +1,210 @@ -[{ - "answer": { - "name": "answer 1" - }, - "name": "question 1", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", - "frames": [{ - "start": 30, - "end": 35 - }, { - "start": 50, - "end": 51 - }] -}, { - "answer": [{ - "name": "answer 2" - }], - "name": "question 2", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", - "frames": [{ - "start": 0, - "end": 5 - }] -}, { - "answer": "a value", - "name": "question 3", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" +[ + { + "answer": { + "name": "answer 1" + }, + "name": "question 1", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", + "frames": [ + { + "start": 30, + "end": 35 + }, + { + "start": 50, + "end": 51 + } + ] }, - "uuid": "e5f32456-bd67-4520-8d3b-cbeb2204bad3" -}, { - "classifications": [], - "name": - "segment 1", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "answer": [ + { + "name": "answer 2" + } + ], + "name": "question 2", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", + "frames": [ + { + "start": 0, + "end": 5 + } + ] }, - "uuid": - "6f7c835a-0139-4896-b73f-66a6baa89e94", - "segments": [{ - "keyframes": [{ - "frame": 1, - "line": [{ - "x": 10.0, - "y": 10.0 - }, { - "x": 100.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }, { - "frame": 5, - "line": [{ - "x": 15.0, - "y": 10.0 - }, { - "x": 50.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 8, - "line": [{ - "x": 100.0, - "y": 10.0 - }, { - "x": 50.0, - "y": 100.0 - }, { - "x": 50.0, - "y": 30.0 - }], - "classifications": [] - }] - }] -}, { - "classifications": [], - "name": - "segment 2", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "answer": "a value", + "name": "question 3", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "e5f32456-bd67-4520-8d3b-cbeb2204bad3" }, - "uuid": - "f963be22-227b-4efe-9be4-2738ed822216", - "segments": [{ - "keyframes": [{ - "frame": 1, - "point": { - "x": 10.0, - "y": 10.0 + { + "classifications": [], + "name": "segment 1", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "6f7c835a-0139-4896-b73f-66a6baa89e94", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "line": [ + { + "x": 10.0, + "y": 10.0 + }, + { + "x": 100.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + }, + { + "frame": 5, + "line": [ + { + "x": 15.0, + "y": 10.0 + }, + { + "x": 50.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + } + ] }, - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 5, - "point": { - "x": 50.0, - "y": 50.0 - }, - "classifications": [] - }, { - "frame": 10, - "point": { - "x": 10.0, - "y": 50.0 - }, - "classifications": [] - }] - }] -}, { - "classifications": [], - "name": - "segment 3", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + { + "keyframes": [ + { + "frame": 8, + "line": [ + { + "x": 100.0, + "y": 10.0 + }, + { + "x": 50.0, + "y": 100.0 + }, + { + "x": 50.0, + "y": 30.0 + } + ], + "classifications": [] + } + ] + } + ] }, - "uuid": - "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", - "segments": [{ - "keyframes": [{ - "frame": 1, - "bbox": { - "top": 10.0, - "left": 5.0, - "height": 100.0, - "width": 150.0 + { + "classifications": [], + "name": "segment 2", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "f963be22-227b-4efe-9be4-2738ed822216", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "point": { + "x": 10.0, + "y": 10.0 + }, + "classifications": [] + } + ] }, - "classifications": [] - }, { - "frame": 5, - "bbox": { - "top": 30.0, - "left": 5.0, - "height": 50.0, - "width": 150.0 - }, - "classifications": [] - }] - }, { - "keyframes": [{ - "frame": 10, - "bbox": { - "top": 300.0, - "left": 200.0, - "height": 400.0, - "width": 150.0 + { + "keyframes": [ + { + "frame": 5, + "point": { + "x": 50.0, + "y": 50.0 + }, + "classifications": [] + }, + { + "frame": 10, + "point": { + "x": 10.0, + "y": 50.0 + }, + "classifications": [] + } + ] + } + ] + }, + { + "classifications": [], + "name": "segment 3", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", + "segments": [ + { + "keyframes": [ + { + "frame": 1, + "bbox": { + "top": 10.0, + "left": 5.0, + "height": 100.0, + "width": 150.0 + }, + "classifications": [] + }, + { + "frame": 5, + "bbox": { + "top": 30.0, + "left": 5.0, + "height": 50.0, + "width": 150.0 + }, + "classifications": [] + } + ] }, - "classifications": [] - }] - }] -}] + { + "keyframes": [ + { + "frame": 10, + "bbox": { + "top": 300.0, + "left": 200.0, + "height": 400.0, + "width": 150.0 + }, + "classifications": [] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_checklist.py b/libs/labelbox/tests/data/serialization/ndjson/test_checklist.py index 612325f34..c4b47427a 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_checklist.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_checklist.py @@ -37,8 +37,10 @@ def test_serialization_min(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) - res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + for i, annotation in enumerate(res.annotations): + annotation.extra.pop("uuid") + assert annotation.value == label.annotations[i].value + assert annotation.name == label.annotations[i].name def test_serialization_with_classification(): @@ -117,8 +119,7 @@ def test_serialization_with_classification(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) - res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + assert label.model_dump(exclude_none=True) == label.model_dump(exclude_none=True) def test_serialization_with_classification_double_nested(): @@ -202,7 +203,7 @@ def test_serialization_with_classification_double_nested(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + assert label.model_dump(exclude_none=True) == label.model_dump(exclude_none=True) def test_serialization_with_classification_double_nested_2(): @@ -231,8 +232,7 @@ def test_serialization_with_classification_double_nested_2(): value=Checklist(answer=[ ClassificationAnswer( name="first_answer", - confidence=0.1, - classifications=[]), + confidence=0.1), ])) ]), ClassificationAnswer(name="third_subchk_answer", @@ -281,5 +281,4 @@ def test_serialization_with_classification_double_nested_2(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) - res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + assert label.model_dump(exclude_none=True) == label.model_dump(exclude_none=True) diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_conversation.py b/libs/labelbox/tests/data/serialization/ndjson/test_conversation.py index 33804ee32..4d2a0416c 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_conversation.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_conversation.py @@ -88,7 +88,7 @@ def test_message_based_radio_classification(label, ndjson): deserialized_label = list(NDJsonConverter().deserialize(ndjson)) deserialized_label[0].annotations[0].extra.pop('uuid') - assert deserialized_label[0].annotations == label[0].annotations + assert deserialized_label[0].model_dump(exclude_none=True) == label[0].model_dump(exclude_none=True) @pytest.mark.parametrize("filename", [ diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_data_gen.py b/libs/labelbox/tests/data/serialization/ndjson/test_data_gen.py index 7b7b33994..186c75223 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_data_gen.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_data_gen.py @@ -43,7 +43,7 @@ def test_deserialize_label(): if hasattr(deserialized_label.annotations[0], 'extra'): # Extra fields are added to deserialized label by default need removed to match deserialized_label.annotations[0].extra = {} - assert deserialized_label.annotations == data_gen_label.annotations + assert deserialized_label.model_dump(exclude_none=True) == data_gen_label.model_dump(exclude_none=True) def test_serialize_deserialize_label(): @@ -52,6 +52,4 @@ def test_serialize_deserialize_label(): if hasattr(deserialized.annotations[0], 'extra'): # Extra fields are added to deserialized label by default need removed to match deserialized.annotations[0].extra = {} - print(data_gen_label.annotations) - print(deserialized.annotations) - assert deserialized.annotations == data_gen_label.annotations + assert deserialized.model_dump(exclude_none=True) == data_gen_label.model_dump(exclude_none=True) diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_dicom.py b/libs/labelbox/tests/data/serialization/ndjson/test_dicom.py index da47127f6..e69c21bae 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_dicom.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_dicom.py @@ -90,11 +90,9 @@ 'masks': { 'frames': [{ 'index': 1, - 'imBytes': None, 'instanceURI': instance_uri_1 }, { 'index': 5, - 'imBytes': None, 'instanceURI': instance_uri_5 }], 'instances': [ @@ -180,7 +178,8 @@ def test_deserialize_nd_dicom_segments(): @pytest.mark.parametrize('label, ndjson', labels_ndjsons) def test_serialize_label(label, ndjson): serialized_label = next(NDJsonConverter().serialize([label])) - serialized_label.pop('uuid') + if "uuid" in serialized_label: + serialized_label.pop('uuid') assert serialized_label == ndjson @@ -189,7 +188,12 @@ def test_deserialize_label(label, ndjson): deserialized_label = next(NDJsonConverter().deserialize([ndjson])) if hasattr(deserialized_label.annotations[0], 'extra'): deserialized_label.annotations[0].extra = {} - assert deserialized_label.annotations == label.annotations + for i, annotation in enumerate(deserialized_label.annotations): + if hasattr(annotation, "frames"): + assert annotation.frames == label.annotations[i].frames + if hasattr(annotation, "value"): + assert annotation.value == label.annotations[i].value + @pytest.mark.parametrize('label', labels) @@ -198,4 +202,8 @@ def test_serialize_deserialize_label(label): deserialized = list(NDJsonConverter.deserialize(serialized)) if hasattr(deserialized[0].annotations[0], 'extra'): deserialized[0].annotations[0].extra = {} - assert deserialized[0].annotations == label.annotations + for i, annotation in enumerate(deserialized[0].annotations): + if hasattr(annotation, "frames"): + assert annotation.frames == label.annotations[i].frames + if hasattr(annotation, "value"): + assert annotation.value == label.annotations[i].value diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_document.py b/libs/labelbox/tests/data/serialization/ndjson/test_document.py index a6aa03908..cdfbbbb88 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_document.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_document.py @@ -76,4 +76,5 @@ def test_pdf_bbox_serialize(): def test_pdf_bbox_deserialize(): deserialized = list(NDJsonConverter.deserialize(bbox_ndjson)) deserialized[0].annotations[0].extra = {} - assert deserialized[0].annotations == bbox_labels[0].annotations + assert deserialized[0].annotations[0].value == bbox_labels[0].annotations[0].value + assert deserialized[0].annotations[0].name == bbox_labels[0].annotations[0].name \ No newline at end of file diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_radio.py b/libs/labelbox/tests/data/serialization/ndjson/test_radio.py index 583eb1fa0..97cb073e0 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_radio.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_radio.py @@ -39,8 +39,11 @@ def test_serialization_with_radio_min(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) - res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + + for i, annotation in enumerate(res.annotations): + annotation.extra.pop("uuid") + assert annotation.value == label.annotations[i].value + assert annotation.name == label.annotations[i].name def test_serialization_with_radio_classification(): @@ -63,7 +66,6 @@ def test_serialization_with_radio_classification(): name="first_sub_radio_answer"))) ]))) ]) - expected = { 'confidence': 0.5, 'name': 'radio_question_geo', @@ -92,4 +94,5 @@ def test_serialization_with_radio_classification(): deserialized = NDJsonConverter.deserialize([res]) res = next(deserialized) res.annotations[0].extra.pop("uuid") - assert res.annotations == label.annotations + assert res.annotations[0].model_dump(exclude_none=True) == label.annotations[0].model_dump(exclude_none=True) + diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_video.py b/libs/labelbox/tests/data/serialization/ndjson/test_video.py index 3eba37e18..ff74db7c1 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_video.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_video.py @@ -12,6 +12,7 @@ from labelbox import parser from labelbox.data.serialization.ndjson.converter import NDJsonConverter +from operator import itemgetter def test_video(): @@ -20,8 +21,13 @@ def test_video(): res = list(NDJsonConverter.deserialize(data)) res = list(NDJsonConverter.serialize(res)) - assert res == [data[2], data[0], data[1], data[3], data[4], data[5]] + + data = sorted(data, key=itemgetter('uuid')) + res = sorted(res, key=itemgetter('uuid')) + pairs = zip(data, res) + for data, res in pairs: + assert data == res def test_video_name_only(): with open('tests/data/assets/ndjson/video_import_name_only.json', @@ -30,7 +36,13 @@ def test_video_name_only(): res = list(NDJsonConverter.deserialize(data)) res = list(NDJsonConverter.serialize(res)) - assert res == [data[2], data[0], data[1], data[3], data[4], data[5]] + + data = sorted(data, key=itemgetter('uuid')) + res = sorted(res, key=itemgetter('uuid')) + + pairs = zip(data, res) + for data, res in pairs: + assert data == res def test_video_classification_global_subclassifications(): @@ -94,9 +106,8 @@ def test_video_classification_global_subclassifications(): deserialized = NDJsonConverter.deserialize(res) res = next(deserialized) annotations = res.annotations - for annotation in annotations: - annotation.extra.pop("uuid") - assert annotations == label.annotations + for i, annotation in enumerate(annotations): + assert annotation.name == label.annotations[i].name def test_video_classification_nesting_bbox(): @@ -228,16 +239,15 @@ def test_video_classification_nesting_bbox(): serialized = NDJsonConverter.serialize([label]) res = [x for x in serialized] - for annotations in res: - annotations.pop("uuid") assert res == expected deserialized = NDJsonConverter.deserialize(res) res = next(deserialized) annotations = res.annotations - for annotation in annotations: + for i, annotation in enumerate(annotations): annotation.extra.pop("uuid") - assert annotations == label.annotations + assert annotation.value == label.annotations[i].value + assert annotation.name == label.annotations[i].name def test_video_classification_point(): @@ -355,16 +365,14 @@ def test_video_classification_point(): serialized = NDJsonConverter.serialize([label]) res = [x for x in serialized] - for annotations in res: - annotations.pop("uuid") assert res == expected deserialized = NDJsonConverter.deserialize(res) res = next(deserialized) annotations = res.annotations - for annotation in annotations: + for i, annotation in enumerate(annotations): annotation.extra.pop("uuid") - assert annotations == label.annotations + assert annotation.value == label.annotations[i].value def test_video_classification_frameline(): @@ -429,38 +437,29 @@ def test_video_classification_frameline(): 'classifications': [], 'segments': [{ 'keyframes': [{ - 'frame': - 13, - 'line': [{ - 'x': 8.0, - 'y': 10.0, - }, { - 'x': 10.0, - 'y': 9.0, - }], 'classifications': [{ 'name': 'radio_question_nested', 'answer': { - 'name': - 'first_radio_question', 'classifications': [{ 'name': 'sub_question_radio', 'answer': [{ 'name': 'sub_answer' }] - }] + }], + 'name': + 'first_radio_question' } - }] - }, { + }], 'frame': - 15, + 13, 'line': [{ - 'x': 18.0, - 'y': 20.0, + 'x': 8.0, + 'y': 10.0, }, { - 'x': 20.0, - 'y': 19.0, - }], + 'x': 10.0, + 'y': 9.0, + }] + }, { 'classifications': [{ 'name': 'nested_checklist_question', @@ -474,8 +473,18 @@ def test_video_classification_frameline(): } }] }] + }], + 'frame': + 15, + 'line': [{ + 'x': 18.0, + 'y': 20.0, + }, { + 'x': 20.0, + 'y': 19.0, }] }, { + 'classifications': [], 'frame': 19, 'line': [{ 'x': 28.0, @@ -483,24 +492,20 @@ def test_video_classification_frameline(): }, { 'x': 30.0, 'y': 29.0, - }], - 'classifications': [] + }] }] }] }] label = Label(data=VideoData(global_key="sample-video-4.mp4",), annotations=bbox_annotation) - serialized = NDJsonConverter.serialize([label]) res = [x for x in serialized] - for annotations in res: - annotations.pop("uuid") assert res == expected deserialized = NDJsonConverter.deserialize(res) res = next(deserialized) annotations = res.annotations - for annotation in annotations: + for i, annotation in enumerate(annotations): annotation.extra.pop("uuid") - assert annotations == label.annotations + assert annotation.value == label.annotations[i].value diff --git a/libs/labelbox/tests/integration/conftest.py b/libs/labelbox/tests/integration/conftest.py index fc623f9fb..5b1f9aa9a 100644 --- a/libs/labelbox/tests/integration/conftest.py +++ b/libs/labelbox/tests/integration/conftest.py @@ -135,9 +135,6 @@ def configured_project_with_complex_ontology(client, initial_dataset, rand_gen, classifications = [ Classification(class_type=Classification.Type.TEXT, name="test-text-class"), - Classification(class_type=Classification.Type.DROPDOWN, - name="test-dropdown-class", - options=options), Classification(class_type=Classification.Type.RADIO, name="test-radio-class", options=options), diff --git a/libs/labelbox/tests/integration/test_foundry.py b/libs/labelbox/tests/integration/test_foundry.py index 560026079..10d6be85b 100644 --- a/libs/labelbox/tests/integration/test_foundry.py +++ b/libs/labelbox/tests/integration/test_foundry.py @@ -75,15 +75,15 @@ def app(foundry_client, unsaved_app): def test_create_app(foundry_client, unsaved_app): app = foundry_client._create_app(unsaved_app) - retrieved_dict = app.dict(exclude={'id', 'created_by'}) - expected_dict = app.dict(exclude={'id', 'created_by'}) + retrieved_dict = app.model_dump(exclude={'id', 'created_by'}) + expected_dict = app.model_dump(exclude={'id', 'created_by'}) assert retrieved_dict == expected_dict def test_get_app(foundry_client, app): retrieved_app = foundry_client._get_app(app.id) - retrieved_dict = retrieved_app.dict(exclude={'created_by'}) - expected_dict = app.dict(exclude={'created_by'}) + retrieved_dict = retrieved_app.model_dump(exclude={'created_by'}) + expected_dict = app.model_dump(exclude={'created_by'}) assert retrieved_dict == expected_dict diff --git a/libs/labelbox/tests/unit/test_unit_delete_batch_data_row_metadata.py b/libs/labelbox/tests/unit/test_unit_delete_batch_data_row_metadata.py index d1a901230..561f8d6b0 100644 --- a/libs/labelbox/tests/unit/test_unit_delete_batch_data_row_metadata.py +++ b/libs/labelbox/tests/unit/test_unit_delete_batch_data_row_metadata.py @@ -8,7 +8,7 @@ def test_dict_delete_data_row_batch(): obj = _DeleteBatchDataRowMetadata( data_row_identifier=UniqueId("abcd"), schema_ids=["clqh77tyk000008l2a9mjesa1", "clqh784br000008jy0yuq04fy"]) - assert obj.dict() == { + assert obj.model_dump() == { "data_row_identifier": { "id": "abcd", "id_type": "ID" @@ -21,7 +21,7 @@ def test_dict_delete_data_row_batch(): obj = _DeleteBatchDataRowMetadata( data_row_identifier=GlobalKey("fegh"), schema_ids=["clqh77tyk000008l2a9mjesa1", "clqh784br000008jy0yuq04fy"]) - assert obj.dict() == { + assert obj.model_dump() == { "data_row_identifier": { "id": "fegh", "id_type": "GKEY" @@ -36,7 +36,7 @@ def test_dict_delete_data_row_batch_by_alias(): obj = _DeleteBatchDataRowMetadata( data_row_identifier=UniqueId("abcd"), schema_ids=["clqh77tyk000008l2a9mjesa1", "clqh784br000008jy0yuq04fy"]) - assert obj.dict(by_alias=True) == { + assert obj.model_dump(by_alias=True) == { "dataRowIdentifier": { "id": "abcd", "idType": "ID" @@ -47,7 +47,7 @@ def test_dict_delete_data_row_batch_by_alias(): obj = _DeleteBatchDataRowMetadata( data_row_identifier=GlobalKey("fegh"), schema_ids=["clqh77tyk000008l2a9mjesa1", "clqh784br000008jy0yuq04fy"]) - assert obj.dict(by_alias=True) == { + assert obj.model_dump(by_alias=True) == { "dataRowIdentifier": { "id": "fegh", "idType": "GKEY" From c816077210b98effe95997544f03ce9cdb4d8781 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Mon, 22 Jul 2024 23:14:15 -0500 Subject: [PATCH 15/34] fixed more test --- libs/labelbox/pyproject.toml | 2 +- .../data/annotation_types/metrics/base.py | 16 +- .../metrics/confusion_matrix.py | 5 +- .../data/serialization/coco/annotation.py | 2 +- .../data/serialization/labelbox_v1/label.py | 8 +- .../data/serialization/labelbox_v1/objects.py | 7 +- .../labelbox/schema/bulk_import_request.py | 3 - .../classification/test_classification.py | 38 +- .../data/annotation_types/test_annotation.py | 1 - .../tests/data/annotation_types/test_label.py | 2 +- .../data/annotation_types/test_metrics.py | 40 +- .../tests/data/annotation_types/test_ner.py | 2 +- .../tests/data/annotation_types/test_video.py | 2 +- .../data/assets/labelbox_v1/video_export.json | 15503 ++++++++-------- .../labelbox_v1/test_document.py | 3 +- .../serialization/labelbox_v1/test_image.py | 1 + .../serialization/labelbox_v1/test_text.py | 3 +- .../labelbox_v1/test_tiled_image.py | 2 +- .../labelbox_v1/test_unknown_media.py | 2 +- 19 files changed, 8148 insertions(+), 7494 deletions(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index 35865e6f5..ef8f595d2 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -86,7 +86,7 @@ unit = "pytest tests/unit" # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/data" } +data = { cmd = "pytest tests/data/serialization/coco" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py index e27284853..7c0636f48 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/base.py @@ -1,7 +1,8 @@ from abc import ABC from typing import Dict, Optional, Any, Union -from pydantic import confloat, BaseModel, model_serializer, field_validator, ValidationError, error_wrappers +from pydantic import confloat, BaseModel, model_serializer, field_validator, error_wrappers +from pydantic_core import ValidationError, InitErrorDetails ConfidenceValue = confloat(ge=0, le=1) @@ -26,12 +27,9 @@ def validate_value(cls, value): if isinstance(value, Dict): if not (MIN_CONFIDENCE_SCORES <= len(value) <= MAX_CONFIDENCE_SCORES): - raise ValidationError([ - error_wrappers(ValueError( - "Number of confidence scores must be greater" - f" than or equal to {MIN_CONFIDENCE_SCORES} and" - f" less than or equal to {MAX_CONFIDENCE_SCORES}. Found {len(value)}" - ), - loc='value') - ], cls) + raise ValueError( + f"Number of confidence scores must be greater than\n \ + or equal to {MIN_CONFIDENCE_SCORES} and less than\n \ + or equal to {MAX_CONFIDENCE_SCORES}. Found {len(value)}" + ) return value diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py index ec1b01984..3e4991a3a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Tuple, Dict, Union +from typing import Optional, Tuple, Dict, Union from pydantic import conint @@ -31,5 +31,4 @@ class ConfusionMatrixMetric(BaseMetric): metric_name: str value: Union[ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue] - aggregation: ConfusionMatrixAggregation = Literal[ - ConfusionMatrixAggregation.CONFUSION_MATRIX] + aggregation: Optional[ConfusionMatrixAggregation] = ConfusionMatrixAggregation.CONFUSION_MATRIX diff --git a/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py b/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py index 32668eaec..a0292e537 100644 --- a/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py +++ b/libs/labelbox/src/labelbox/data/serialization/coco/annotation.py @@ -43,7 +43,7 @@ def get_annotation_lookup(annotations): class SegmentInfo(BaseModel): id: int category_id: int - area: int + area: Union[float, int] bbox: Tuple[float, float, float, float] #[x,y,w,h], iscrowd: int = 0 diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py index 7dc18501d..4035871a2 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/label.py @@ -9,7 +9,7 @@ from ...annotation_types.label import Label from .classification import LBV1Classifications from .objects import LBV1Objects, LBV1TextEntity -from pydantic import Field, BaseModel, ConfigDict +from pydantic import Field, BaseModel, ConfigDict, model_serializer from pydantic.alias_generators import to_camel @@ -152,14 +152,14 @@ def to_common(self) -> Label: annotations.extend(lbl.to_common()) else: annotations = self.label.to_common() - + return Label(data=self._data_row_to_common(), uid=self.id, annotations=annotations, extra={ field.alias: getattr(self, field_name) - for field_name, field in self.__fields__.items() - if field.field_info.extra.get('extra_field') + for field_name, field in self.model_fields.items() + if isinstance(field.json_schema_extra, Dict) and field.json_schema_extra["extra_field"] }) @classmethod diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py index 44f9d913b..21c72e18d 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/objects.py @@ -19,7 +19,7 @@ class LBV1ObjectBase(LBV1Feature): color: Optional[str] = None - instanceURI: Optional[str] = None + instanceURI: Optional[str] = Field(default=None, serialization_alias="instanceURI") classifications: List[Union[LBV1Text, LBV1Radio, LBV1Checklist]] = [] page: Optional[int] = None @@ -30,7 +30,10 @@ def serialize_model(self, handler): res = handler(self) # This means these are not video frames .. if self.instanceURI is None: - res.pop('instanceURI') + if "instanceURI" in res: + res.pop('instanceURI') + if "instanceuri" in res: + res.pop("instanceuri") return res @field_validator('classifications', mode="before") diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index 68fe6cc2a..b95b72148 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -513,9 +513,6 @@ def get_mal_schemas(ontology): return valid_feature_schemas_by_schema_id, valid_feature_schemas_by_name -LabelboxID: Type[str] = Annotated[str, StringConstraints(min_length=25, max_length=25)] - - class Bbox(BaseModel): top: float left: float diff --git a/libs/labelbox/tests/data/annotation_types/classification/test_classification.py b/libs/labelbox/tests/data/annotation_types/classification/test_classification.py index 9a4ea0d39..066cf91bd 100644 --- a/libs/labelbox/tests/data/annotation_types/classification/test_classification.py +++ b/libs/labelbox/tests/data/annotation_types/classification/test_classification.py @@ -11,7 +11,7 @@ def test_classification_answer(): with pytest.raises(ValidationError): ClassificationAnswer() - feature_schema_id = "schema_id" + feature_schema_id = "immunoelectrophoretically" name = "my_feature" confidence = 0.9 custom_metrics = [{'name': 'metric1', 'value': 2}] @@ -22,7 +22,7 @@ def test_classification_answer(): assert answer.feature_schema_id is None assert answer.name == name assert answer.confidence == confidence - assert [answer.custom_metrics[0].model_dump()] == custom_metrics + assert [answer.custom_metrics[0].model_dump(exclude_none=True)] == custom_metrics answer = ClassificationAnswer(feature_schema_id=feature_schema_id, name=name) @@ -35,7 +35,7 @@ def test_classification(): answer = "1234" classification = ClassificationAnnotation(value=Text(answer=answer), name="a classification") - assert classification.model_dump()['value']['answer'] == answer + assert classification.model_dump(exclude_none=True)['value']['answer'] == answer with pytest.raises(ValidationError): ClassificationAnnotation() @@ -43,49 +43,43 @@ def test_classification(): def test_subclass(): answer = "1234" - feature_schema_id = "11232" + feature_schema_id = "immunoelectrophoretically" name = "my_feature" with pytest.raises(ValidationError): # Should have feature schema info classification = ClassificationAnnotation(value=Text(answer=answer)) classification = ClassificationAnnotation(value=Text(answer=answer), name=name) - print(classification.model_dump()) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'name': name, - 'feature_schema_id': None, 'extra': {}, 'value': { 'answer': answer, }, - 'message_id': None, } classification = ClassificationAnnotation( value=Text(answer=answer), name=name, feature_schema_id=feature_schema_id) - assert classification.model_dump() == { - 'name': None, + assert classification.model_dump(exclude_none=True) == { 'feature_schema_id': feature_schema_id, 'extra': {}, 'value': { 'answer': answer, }, 'name': name, - 'message_id': None, } classification = ClassificationAnnotation( value=Text(answer=answer), feature_schema_id=feature_schema_id, name=name) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, 'value': { 'answer': answer, }, - 'message_id': None, } @@ -96,7 +90,7 @@ def test_radio(): 'name': 'metric1', 'value': 0.99 }]) - feature_schema_id = "feature_schema_id" + feature_schema_id = "immunoelectrophoretically" name = "my_feature" with pytest.raises(ValidationError): @@ -107,10 +101,9 @@ def test_radio(): classification = Radio(answer=[answer]) classification = Radio(answer=answer) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'answer': { 'name': answer.name, - 'feature_schema_id': None, 'extra': {}, 'confidence': 0.81, 'custom_metrics': [{ @@ -127,7 +120,7 @@ def test_radio(): 'name': 'metric1', 'value': 0.99 }]) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, @@ -138,7 +131,6 @@ def test_radio(): 'value': { 'answer': { 'name': answer.name, - 'feature_schema_id': None, 'extra': {}, 'confidence': 0.81, 'custom_metrics': [{ @@ -147,7 +139,6 @@ def test_radio(): }] }, }, - 'message_id': None, } @@ -158,7 +149,7 @@ def test_checklist(): 'name': 'metric1', 'value': 2 }]) - feature_schema_id = "feature_schema_id" + feature_schema_id = "immunoelectrophoretically" name = "my_feature" with pytest.raises(ValidationError): @@ -168,10 +159,9 @@ def test_checklist(): classification = Checklist(answer=answer) classification = Checklist(answer=[answer]) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'answer': [{ 'name': answer.name, - 'feature_schema_id': None, 'extra': {}, 'confidence': 0.99, 'custom_metrics': [{ @@ -185,14 +175,13 @@ def test_checklist(): feature_schema_id=feature_schema_id, name=name, ) - assert classification.model_dump() == { + assert classification.model_dump(exclude_none=True) == { 'name': name, 'feature_schema_id': feature_schema_id, 'extra': {}, 'value': { 'answer': [{ 'name': answer.name, - 'feature_schema_id': None, 'extra': {}, 'confidence': 0.99, 'custom_metrics': [{ @@ -201,5 +190,4 @@ def test_checklist(): }], }] }, - 'message_id': None, } diff --git a/libs/labelbox/tests/data/annotation_types/test_annotation.py b/libs/labelbox/tests/data/annotation_types/test_annotation.py index 38a907489..926d8bc97 100644 --- a/libs/labelbox/tests/data/annotation_types/test_annotation.py +++ b/libs/labelbox/tests/data/annotation_types/test_annotation.py @@ -95,4 +95,3 @@ def test_confidence_value_range_validation(): with pytest.raises(ValueError) as e: ObjectAnnotation(value=line, name=name, confidence=14) - assert e.value.errors()[0]['msg'] == 'must be a number within [0,1] range' diff --git a/libs/labelbox/tests/data/annotation_types/test_label.py b/libs/labelbox/tests/data/annotation_types/test_label.py index 8d8f8c836..f0957fcee 100644 --- a/libs/labelbox/tests/data/annotation_types/test_label.py +++ b/libs/labelbox/tests/data/annotation_types/test_label.py @@ -207,6 +207,6 @@ def test_prompt_classification_validation(): name="prompt text", value=PromptText(answer="test") ) - with pytest.raises(ValidationError) as e_info: + with pytest.raises(TypeError) as e_info: label = Label(data={"global_key": global_key}, annotations=[prompt_text, prompt_text_2]) diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index d173c314e..7bc7c78ba 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -16,25 +16,15 @@ def test_legacy_scalar_metric(): annotations=[metric]) expected = { 'data': { - 'external_id': None, 'uid': 'ckrmd9q8g000009mg6vej7hzg', - 'global_key': None, - 'im_bytes': None, - 'file_path': None, - 'url': None, - 'arr': None, - 'media_attributes': None, - 'metadata': None, }, 'annotations': [{ 'value': 10.0, 'extra': {}, }], 'extra': {}, - 'uid': None, - 'is_benchmark_reference': False } - assert label.model_dump() == expected + assert label.model_dump(exclude_none=True) == expected # TODO: Test with confidence @@ -68,15 +58,7 @@ def test_custom_scalar_metric(feature_name, subclass_name, aggregation, value): annotations=[metric]) expected = { 'data': { - 'external_id': None, 'uid': 'ckrmd9q8g000009mg6vej7hzg', - 'global_key': None, - 'im_bytes': None, - 'file_path': None, - 'url': None, - 'arr': None, - 'media_attributes': None, - 'metadata': None, }, 'annotations': [{ 'value': @@ -93,11 +75,8 @@ def test_custom_scalar_metric(feature_name, subclass_name, aggregation, value): 'extra': {} }], 'extra': {}, - 'uid': None, - 'is_benchmark_reference': False } - - assert label.model_dump() == expected + assert label.model_dump(exclude_none=True) == expected @pytest.mark.parametrize('feature_name,subclass_name,aggregation,value', [ @@ -126,15 +105,7 @@ def test_custom_confusison_matrix_metric(feature_name, subclass_name, annotations=[metric]) expected = { 'data': { - 'external_id': None, 'uid': 'ckrmd9q8g000009mg6vej7hzg', - 'global_key': None, - 'im_bytes': None, - 'file_path': None, - 'url': None, - 'arr': None, - 'media_attributes': None, - 'metadata': None, }, 'annotations': [{ 'value': @@ -151,17 +122,14 @@ def test_custom_confusison_matrix_metric(feature_name, subclass_name, 'extra': {} }], 'extra': {}, - 'uid': None, - 'is_benchmark_reference': False } - assert label.model_dump() == expected + assert label.model_dump(exclude_none=True) == expected def test_name_exists(): # Name is only required for ConfusionMatrixMetric for now. with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric(value=[0, 1, 2, 3]) - assert "field required (type=value_error.missing)" in str(exc_info.value) def test_invalid_aggregations(): @@ -170,12 +138,10 @@ def test_invalid_aggregations(): metric_name="invalid aggregation", value=0.1, aggregation=ConfusionMatrixAggregation.CONFUSION_MATRIX) - assert "value is not a valid enumeration member" in str(exc_info.value) with pytest.raises(ValidationError) as exc_info: metric = ConfusionMatrixMetric(metric_name="invalid aggregation", value=[0, 1, 2, 3], aggregation=ScalarMetricAggregation.SUM) - assert "value is not a valid enumeration member" in str(exc_info.value) def test_invalid_number_of_confidence_scores(): diff --git a/libs/labelbox/tests/data/annotation_types/test_ner.py b/libs/labelbox/tests/data/annotation_types/test_ner.py index 9b393077d..9619689b1 100644 --- a/libs/labelbox/tests/data/annotation_types/test_ner.py +++ b/libs/labelbox/tests/data/annotation_types/test_ner.py @@ -21,7 +21,7 @@ def test_document_entity(): def test_conversation_entity(): - conversation_entity = ConversationEntity(message_id=1, start=0, end=1) + conversation_entity = ConversationEntity(message_id="1", start=0, end=1) assert conversation_entity.message_id == "1" assert conversation_entity.start == 0 diff --git a/libs/labelbox/tests/data/annotation_types/test_video.py b/libs/labelbox/tests/data/annotation_types/test_video.py index 39aca1073..f61dc7ec7 100644 --- a/libs/labelbox/tests/data/annotation_types/test_video.py +++ b/libs/labelbox/tests/data/annotation_types/test_video.py @@ -13,7 +13,7 @@ def test_mask_frame(): def test_mask_instance(): mask_instance = lb_types.MaskInstance(color_rgb=(0, 0, 255), name="mask1") - assert mask_instance.model_dump(by_alias=True) == { + assert mask_instance.model_dump(by_alias=True, exclude_none=True) == { 'colorRGB': (0, 0, 255), 'name': 'mask1' } diff --git a/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json b/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json index 8f863ae7e..76235c40f 100644 --- a/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json +++ b/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json @@ -5,7407 +5,8108 @@ "Media Attributes": {}, "Data Split": null, "Labeled Data": "https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2Fb8837f3b-b071-98d9-645e-2e2c0302393b-jellyfish2-100-110.mp4?Expires=1627663739196&KeyName=labelbox-assets-key-3&Signature=JJ8HOcm57D7OclbC795cyjrrA3Q", - "Label": [{ - "frameNumber": 1, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 582, - "left": 1644, - "height": 340, - "width": 212 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 712, - "left": 1256, - "height": 204, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 47, - "left": 155, - "height": 381, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 546, - "height": 263, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 361, - "height": 183, - "width": 207 - }, - "classifications": [] - }] - }, { - "frameNumber": 2, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 595, - "left": 1635, - "height": 340, - "width": 212 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 719, - "left": 1246, - "height": 204, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 45, - "left": 148, - "height": 381, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 540, - "height": 262, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 353, - "height": 184, - "width": 209 - }, - "classifications": [] - }] - }, { - "frameNumber": 3, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 600, - "left": 1628, - "height": 326, - "width": 212 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1233, - "height": 188, - "width": 332 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 46, - "left": 130, - "height": 381, - "width": 341 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 732, - "left": 536, - "height": 262, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 346, - "height": 183, - "width": 211 - }, - "classifications": [] - }] - }, { - "frameNumber": 4, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 604, - "left": 1619, - "height": 322, - "width": 214 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1225, - "height": 180, - "width": 336 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 37, - "left": 123, - "height": 386, - "width": 343 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 732, - "left": 536, - "height": 269, - "width": 288 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 338, - "height": 185, - "width": 216 - }, - "classifications": [] - }] - }, { - "frameNumber": 5, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 619, - "left": 1606, - "height": 322, - "width": 214 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 729, - "left": 1208, - "height": 180, - "width": 336 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 36, - "left": 116, - "height": 386, - "width": 343 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 529, - "height": 269, - "width": 288 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 493, - "left": 332, - "height": 185, - "width": 216 - }, - "classifications": [] - }] - }, { - "frameNumber": 6, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 1597, - "height": 322, - "width": 214 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 1195, - "height": 180, - "width": 336 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 30, - "left": 108, - "height": 386, - "width": 343 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 734.5, - "left": 522, - "height": 269, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 491, - "left": 326, - "height": 185, - "width": 216 - }, - "classifications": [] - }] - }, { - "frameNumber": 7, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 632, - "left": 1586, - "height": 322, - "width": 214 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 1189, - "height": 175, - "width": 323 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 30, - "left": 86, - "height": 367, - "width": 354 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 515, - "height": 269, - "width": 292 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 490, - "left": 316, - "height": 183, - "width": 218 - }, - "classifications": [] - }] - }, { - "frameNumber": 8, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 634, - "left": 1582, - "height": 321, - "width": 209 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 751, - "left": 1188, - "height": 170, - "width": 316 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 26, - "left": 78, - "height": 367, - "width": 354 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 500, - "height": 266, - "width": 302 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 488, - "left": 311, - "height": 183, - "width": 218 - }, - "classifications": [] - }] - }, { - "frameNumber": 9, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 641, - "left": 1575, - "height": 321, - "width": 209 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 1188, - "height": 168, - "width": 307 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 23, - "left": 63, - "height": 372, - "width": 362 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 500, - "height": 270, - "width": 297 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 488, - "left": 305, - "height": 182, - "width": 219 - }, - "classifications": [] - }] - }, { - "frameNumber": 10, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 648, - "left": 1563, - "height": 315, - "width": 203 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 1172, - "height": 172, - "width": 309 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 14, - "left": 48, - "height": 371, - "width": 366 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 493, - "height": 271, - "width": 304 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 486, - "left": 292, - "height": 184, - "width": 224 - }, - "classifications": [] - }] - }, { - "frameNumber": 11, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 1555, - "height": 317, - "width": 208 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 1169, - "height": 174, - "width": 294 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 11, - "left": 47, - "height": 374, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 484, - "height": 271, - "width": 304 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 485, - "left": 287, - "height": 184, - "width": 224 - }, - "classifications": [] - }] - }, { - "frameNumber": 12, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 1545, - "height": 317, - "width": 204 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 1162, - "height": 168, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 34, - "height": 374, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 476, - "height": 271, - "width": 304 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 479, - "left": 278, - "height": 184, - "width": 224 - }, - "classifications": [] - }] - }, { - "frameNumber": 13, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 663, - "left": 1538, - "height": 317, - "width": 204 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 749, - "left": 1154, - "height": 173, - "width": 289 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 27, - "height": 374, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 473, - "height": 271, - "width": 304 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 476, - "left": 271, - "height": 183, - "width": 229 - }, - "classifications": [] - }] - }, { - "frameNumber": 14, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 666, - "left": 1531, - "height": 314, - "width": 211 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 748, - "left": 1147, - "height": 176, - "width": 283 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 23, - "height": 312, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 470, - "height": 271, - "width": 304 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 470, - "left": 264, - "height": 187, - "width": 231 - }, - "classifications": [] - }] - }, { - "frameNumber": 15, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 670, - "left": 1519, - "height": 316, - "width": 207 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 742, - "left": 1136, - "height": 187, - "width": 272 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 23, - "height": 281, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 457, - "height": 278, - "width": 312 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 464, - "left": 254, - "height": 193, - "width": 235 - }, - "classifications": [] - }] - }, { - "frameNumber": 16, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 674, - "left": 1512, - "height": 311, - "width": 204 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 1129, - "height": 190, - "width": 279 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 19, - "height": 276, - "width": 356 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 457, - "height": 277, - "width": 306 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 457, - "left": 245, - "height": 189, - "width": 238 - }, - "classifications": [] - }] - }, { - "frameNumber": 17, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 678, - "left": 1502, - "height": 310, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1118, - "height": 198, - "width": 267 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 271, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 725, - "left": 447, - "height": 277, - "width": 306 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 453, - "left": 236, - "height": 189, - "width": 238 - }, - "classifications": [] - }] - }, { - "frameNumber": 18, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 679, - "left": 1496, - "height": 310, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1110, - "height": 203, - "width": 262 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 0, - "left": 0, - "height": 265.5, - "width": 360 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 725, - "left": 438, - "height": 276, - "width": 315 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 450, - "left": 227, - "height": 191, - "width": 244 - }, - "classifications": [] - }] - }, { - "frameNumber": 19, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 685, - "left": 1489, - "height": 317, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 730, - "left": 1099, - "height": 206, - "width": 273 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 260, - "width": 353 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 438, - "height": 271, - "width": 307 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 449, - "left": 222, - "height": 183, - "width": 244 - }, - "classifications": [] - }] - }, { - "frameNumber": 20, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 689, - "left": 1477, - "height": 317, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 1086, - "height": 213, - "width": 260 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 258, - "width": 345 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 721, - "left": 431, - "height": 271, - "width": 308 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 448, - "left": 217, - "height": 177, - "width": 244 - }, - "classifications": [] - }] - }, { - "frameNumber": 21, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 690, - "left": 1470, - "height": 317, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1077, - "height": 213, - "width": 260 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 259, - "width": 335 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 423, - "height": 271, - "width": 308 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 446, - "left": 212, - "height": 177, - "width": 244 - }, - "classifications": [] - }] - }, { - "frameNumber": 22, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 697, - "left": 1458, - "height": 317, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1065, - "height": 213, - "width": 260 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 227, - "width": 313 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 420, - "height": 250, - "width": 302 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 446, - "left": 212, - "height": 164, - "width": 236 - }, - "classifications": [] - }] - }, { - "frameNumber": 23, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 701, - "left": 1449, - "height": 317, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 727, - "left": 1055, - "height": 219, - "width": 253 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 214, - "width": 307 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 417, - "height": 250, - "width": 302 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 432, - "left": 190, - "height": 147, - "width": 255 - }, - "classifications": [] - }] - }, { - "frameNumber": 24, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 1447, - "height": 321, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 1049, - "height": 229, - "width": 250 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 202, - "width": 282 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 408, - "height": 235, - "width": 308 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 448, - "left": 209, - "height": 150, - "width": 228 - }, - "classifications": [] - }] - }, { - "frameNumber": 25, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 708, - "left": 1433, - "height": 321, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1035, - "height": 229, - "width": 251 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 198, - "width": 272 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 759, - "left": 399, - "height": 234, - "width": 317 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 424, - "left": 170, - "height": 148, - "width": 262 - }, - "classifications": [] - }] - }, { - "frameNumber": 26, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 714, - "left": 1425, - "height": 313, - "width": 194 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 1027, - "height": 240, - "width": 248 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 190, - "width": 272 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 392, - "height": 227, - "width": 322 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 413, - "left": 163, - "height": 152, - "width": 230 - }, - "classifications": [] - }] - }, { - "frameNumber": 27, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 719, - "left": 1413, - "height": 313, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 1018, - "height": 235, - "width": 238 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 208, - "width": 284 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 754, - "left": 384.5, - "height": 228.5, - "width": 328.5 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 409, - "left": 151, - "height": 178, - "width": 268 - }, - "classifications": [] - }] - }, { - "frameNumber": 28, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1408, - "height": 313, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 735, - "left": 1011, - "height": 217, - "width": 237 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 206, - "width": 281 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 377, - "height": 230, - "width": 335 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 409, - "left": 148, - "height": 178, - "width": 268 - }, - "classifications": [] - }] - }, { - "frameNumber": 29, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 1398, - "height": 313, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 1006, - "height": 205, - "width": 233 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 200, - "width": 274 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 370, - "height": 232, - "width": 342 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 401, - "left": 138, - "height": 181, - "width": 275 - }, - "classifications": [] - }] - }, { - "frameNumber": 30, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1389, - "height": 313, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 751, - "left": 993, - "height": 182, - "width": 230 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 191, - "width": 261 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 745, - "left": 368, - "height": 232, - "width": 342 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 397, - "left": 132, - "height": 181, - "width": 275 - }, - "classifications": [] - }] - }, { - "frameNumber": 31, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1381, - "height": 308, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 988, - "height": 181, - "width": 216 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 190, - "width": 258 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 368, - "height": 243, - "width": 341 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 394, - "left": 125, - "height": 181, - "width": 275 - }, - "classifications": [] - }] - }, { - "frameNumber": 32, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 1369, - "height": 308, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 769, - "left": 979, - "height": 167, - "width": 204 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 181, - "width": 247 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 367, - "height": 251, - "width": 341 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 387, - "left": 116, - "height": 182, - "width": 280 - }, - "classifications": [] - }] - }, { - "frameNumber": 33, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 1361, - "height": 308, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 774, - "left": 973, - "height": 163, - "width": 199 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 176, - "width": 239 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 720, - "left": 368, - "height": 261, - "width": 340 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 383, - "left": 106, - "height": 180, - "width": 286 - }, - "classifications": [] - }] - }, { - "frameNumber": 34, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 1353, - "height": 308, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 778, - "left": 967, - "height": 162, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 171, - "width": 235 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 718, - "left": 364, - "height": 257, - "width": 344 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 379, - "left": 100, - "height": 183, - "width": 287 - }, - "classifications": [] - }] - }, { - "frameNumber": 35, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 749, - "left": 1343, - "height": 308, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 795, - "left": 957, - "height": 148, - "width": 178 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 160, - "width": 225 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 711, - "left": 363, - "height": 256, - "width": 343 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 375, - "left": 93.5, - "height": 187, - "width": 289.5 - }, - "classifications": [] - }] - }, { - "frameNumber": 36, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 752, - "left": 1337, - "height": 309, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 796, - "left": 948, - "height": 149, - "width": 185 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 150, - "width": 216 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 710, - "left": 365, - "height": 269, - "width": 340 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 371, - "left": 87, - "height": 191, - "width": 292 - }, - "classifications": [] - }] - }, { - "frameNumber": 37, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 1324, - "height": 302, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 794, - "left": 935, - "height": 153, - "width": 177 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 131, - "width": 206 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 704, - "left": 360, - "height": 275, - "width": 342 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 365, - "left": 76, - "height": 194, - "width": 297 - }, - "classifications": [] - }] - }, { - "frameNumber": 38, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 763, - "left": 1318, - "height": 302, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 789, - "left": 928, - "height": 160, - "width": 174 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 106, - "width": 199 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 702, - "left": 357, - "height": 277, - "width": 341 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 363, - "left": 70, - "height": 199, - "width": 300 - }, - "classifications": [] - }] - }, { - "frameNumber": 39, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 1310, - "height": 302, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 786, - "left": 918, - "height": 164, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 38, - "width": 134 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 695, - "left": 357, - "height": 282, - "width": 340 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 359, - "left": 64, - "height": 200, - "width": 302 - }, - "classifications": [] - }] - }, { - "frameNumber": 40, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 770, - "left": 1299, - "height": 302, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 775, - "left": 905, - "height": 177, - "width": 177 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 16, - "width": 111 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 694, - "left": 354, - "height": 282, - "width": 338 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 353, - "left": 56, - "height": 203, - "width": 305 - }, - "classifications": [] - }] - }, { - "frameNumber": 41, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 772, - "left": 1289, - "height": 302, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 896, - "height": 185, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 688.5, - "left": 351.5, - "height": 287, - "width": 338.5 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 350, - "left": 51, - "height": 203, - "width": 306 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 321, - "left": 569, - "height": 125, - "width": 109 - }, - "classifications": [] - }] - }, { - "frameNumber": 42, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 775, - "left": 1281, - "height": 297, - "width": 188 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 884, - "height": 196, - "width": 175 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 683, - "left": 349, - "height": 292, - "width": 339 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 342, - "left": 41, - "height": 204, - "width": 310 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 317, - "left": 559.5, - "height": 126, - "width": 111 - }, - "classifications": [] - }] - }, { - "frameNumber": 43, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 778, - "left": 1273, - "height": 297, - "width": 188 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 748, - "left": 875, - "height": 202, - "width": 152 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 682, - "left": 346, - "height": 292, - "width": 339 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 335, - "left": 37, - "height": 204, - "width": 310 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 313, - "left": 550, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 44, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 779, - "left": 1266, - "height": 293, - "width": 188 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 741, - "left": 865, - "height": 211, - "width": 158 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 681, - "left": 345, - "height": 292, - "width": 339 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 331, - "left": 33, - "height": 204, - "width": 310 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 309, - "left": 543, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 45, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 785, - "left": 1255, - "height": 293, - "width": 188 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 734, - "left": 855.5, - "height": 217.5, - "width": 160 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 672, - "left": 340, - "height": 296, - "width": 339 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 322, - "left": 28, - "height": 211, - "width": 311 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 303, - "left": 532, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 46, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 784, - "left": 1245, - "height": 293, - "width": 188 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 727, - "left": 846, - "height": 224, - "width": 162 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 669, - "left": 344, - "height": 297, - "width": 333 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 314, - "left": 23, - "height": 211, - "width": 311 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 298, - "left": 526, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 47, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 787, - "left": 1234, - "height": 290, - "width": 186 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 832, - "height": 224, - "width": 165 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 668, - "left": 339, - "height": 297, - "width": 333 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 306, - "left": 12, - "height": 211, - "width": 315 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 291, - "left": 514, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 48, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 790, - "left": 1227, - "height": 286, - "width": 187 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 714, - "left": 824, - "height": 235, - "width": 167 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 667, - "left": 335, - "height": 297, - "width": 333 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 301, - "left": 7, - "height": 211, - "width": 315 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 289, - "left": 506, - "height": 127, - "width": 113 - }, - "classifications": [] - }] - }, { - "frameNumber": 49, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 792, - "left": 1216, - "height": 286, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 710, - "left": 815, - "height": 238, - "width": 167 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 664, - "left": 337, - "height": 297, - "width": 327 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 298, - "left": 0, - "height": 214, - "width": 319 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 285, - "left": 498, - "height": 127, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 50, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 797, - "left": 1205, - "height": 283, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 815, - "height": 239, - "width": 157 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 658, - "left": 334, - "height": 302, - "width": 327 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 290, - "left": 0, - "height": 217, - "width": 312 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 281, - "left": 485, - "height": 127, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 51, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 797, - "left": 1197, - "height": 283, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 812, - "height": 240, - "width": 157 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 328, - "height": 302, - "width": 327 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 284, - "left": 0, - "height": 223, - "width": 310 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 277, - "left": 478, - "height": 127, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 52, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 801, - "left": 1183, - "height": 279, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 802, - "height": 243, - "width": 150 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 322, - "height": 299, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 279, - "left": 0, - "height": 220, - "width": 302 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 271, - "left": 465, - "height": 129, - "width": 117 - }, - "classifications": [] - }] - }, { - "frameNumber": 53, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 807, - "left": 1177, - "height": 273, - "width": 191 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 802, - "height": 243, - "width": 144 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 659, - "left": 316, - "height": 297, - "width": 333 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 274, - "left": 0, - "height": 225, - "width": 298 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 270, - "left": 456, - "height": 129, - "width": 117 - }, - "classifications": [] - }] - }, { - "frameNumber": 54, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 807, - "left": 1167, - "height": 273, - "width": 191 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 704, - "left": 792, - "height": 247, - "width": 145 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 312, - "height": 306, - "width": 332 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 270, - "left": 0, - "height": 229, - "width": 295 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 266, - "left": 448, - "height": 129, - "width": 117 - }, - "classifications": [] - }] - }, { - "frameNumber": 55, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 1156, - "height": 267, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 706, - "left": 783, - "height": 247, - "width": 145 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 310, - "height": 304, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 260, - "left": 0, - "height": 231, - "width": 290 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 261, - "left": 435, - "height": 129, - "width": 118 - }, - "classifications": [] - }] - }, { - "frameNumber": 56, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 1148, - "height": 267, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 706, - "left": 784, - "height": 248, - "width": 147 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 308, - "height": 304, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 257, - "left": 0, - "height": 234, - "width": 286 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 260, - "left": 428, - "height": 129, - "width": 118 - }, - "classifications": [] - }] - }, { - "frameNumber": 57, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 819, - "left": 1134, - "height": 261, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 776, - "height": 248, - "width": 146 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 647, - "left": 303, - "height": 304, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 250, - "left": 0, - "height": 235, - "width": 283 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 255, - "left": 415, - "height": 128, - "width": 120 - }, - "classifications": [] - }] - }, { - "frameNumber": 58, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 822, - "left": 1127, - "height": 258, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 775, - "height": 250, - "width": 138 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 648, - "left": 300, - "height": 304, - "width": 330 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 246, - "left": 0, - "height": 236, - "width": 279 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 250, - "left": 406, - "height": 128, - "width": 120 - }, - "classifications": [] - }] - }, { - "frameNumber": 59, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 825, - "left": 1120, - "height": 255, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 709.5, - "left": 780, - "height": 249, - "width": 124 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 645, - "left": 297.5, - "height": 306.5, - "width": 328 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 244, - "left": 11, - "height": 238, - "width": 265 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 248, - "left": 396, - "height": 127.5, - "width": 122 - }, - "classifications": [] - }] - }, { - "frameNumber": 60, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 828, - "left": 1108, - "height": 252, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 712, - "left": 785, - "height": 248, - "width": 110 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 642, - "left": 295, - "height": 309, - "width": 326 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 238, - "left": 24, - "height": 244, - "width": 248 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 246, - "left": 386, - "height": 127, - "width": 124 - }, - "classifications": [] - }] - }, { - "frameNumber": 61, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 832, - "left": 1099, - "height": 248, - "width": 191 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 716, - "left": 790, - "height": 241, - "width": 98 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 640, - "left": 279.5, - "height": 310, - "width": 340 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 233, - "left": 41, - "height": 243, - "width": 227 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 243, - "left": 379, - "height": 128, - "width": 123 - }, - "classifications": [] - }] - }, { - "frameNumber": 62, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 836, - "left": 1088, - "height": 244, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 894, - "left": 777, - "height": 63, - "width": 99 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 638, - "left": 264, - "height": 311, - "width": 354 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 227, - "left": 43, - "height": 234, - "width": 221 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 238, - "left": 367, - "height": 128, - "width": 123 - }, - "classifications": [] - }] - }, { - "frameNumber": 63, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 840, - "left": 1081, - "height": 240, - "width": 191 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 776, - "height": 60, - "width": 94 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 638, - "left": 256, - "height": 312, - "width": 359 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 226, - "left": 38, - "height": 225, - "width": 226 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 235, - "left": 361, - "height": 128, - "width": 123 - }, - "classifications": [] - }] - }, { - "frameNumber": 64, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 843, - "left": 1074, - "height": 237, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 860, - "left": 723, - "height": 85.5, - "width": 131 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 636.5, - "left": 250, - "height": 313, - "width": 363 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 222, - "left": 31, - "height": 222, - "width": 229 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 230, - "left": 361, - "height": 131, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 65, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 847, - "left": 1064, - "height": 233, - "width": 190 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 828, - "left": 670, - "height": 111, - "width": 168 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 635, - "left": 244, - "height": 314, - "width": 367 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 216, - "left": 29, - "height": 190, - "width": 228 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 227, - "left": 350, - "height": 131, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 66, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1054, - "height": 228, - "width": 192 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 662, - "height": 116, - "width": 169 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 634.5, - "left": 239, - "height": 313, - "width": 369 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 214, - "left": 29, - "height": 163, - "width": 227 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 222, - "left": 343, - "height": 131, - "width": 115 - }, - "classifications": [] - }] - }, { - "frameNumber": 67, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1042, - "height": 228, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 808, - "left": 651, - "height": 122, - "width": 166 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 634, - "left": 234, - "height": 312, - "width": 371 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 209, - "left": 23, - "height": 161, - "width": 229 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 220, - "left": 337, - "height": 130, - "width": 110 - }, - "classifications": [] - }] - }, { - "frameNumber": 68, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1035, - "height": 228, - "width": 193 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 808, - "left": 651, - "height": 122, - "width": 156 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 224, - "height": 322, - "width": 377 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 203, - "left": 24, - "height": 163, - "width": 227 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 217, - "left": 329, - "height": 130, - "width": 108 - }, - "classifications": [] - }] - }, { - "frameNumber": 69, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 857, - "left": 1028, - "height": 223, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 802, - "left": 637, - "height": 127, - "width": 158 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 623, - "left": 220.667, - "height": 321.667, - "width": 379.333 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 203, - "left": 19, - "height": 153, - "width": 231 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 213, - "left": 325, - "height": 130, - "width": 108 - }, - "classifications": [] - }] - }, { - "frameNumber": 70, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 864, - "left": 1016, - "height": 216, - "width": 198 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 802, - "left": 629.5, - "height": 129.5, - "width": 153 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 623, - "left": 217.333, - "height": 321.333, - "width": 381.667 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 202.5, - "left": 19.5, - "height": 142.5, - "width": 228 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 212, - "left": 315, - "height": 124.5, - "width": 108 - }, - "classifications": [] - }] - }, { - "frameNumber": 71, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 864, - "left": 1009, - "height": 216, - "width": 198 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 802, - "left": 622, - "height": 132, - "width": 148 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 214, - "height": 321, - "width": 384 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 202, - "left": 20, - "height": 132, - "width": 225 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 211, - "left": 305, - "height": 119, - "width": 108 - }, - "classifications": [] - }] - }, { - "frameNumber": 72, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 868, - "left": 994, - "height": 212, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 798, - "left": 610, - "height": 138, - "width": 165 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 620, - "left": 203, - "height": 323, - "width": 388 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 189, - "left": 16, - "height": 137, - "width": 227 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 212, - "left": 294, - "height": 114, - "width": 108 - }, - "classifications": [] - }] - }, { - "frameNumber": 73, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 873, - "left": 987, - "height": 207, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 787, - "left": 603, - "height": 151, - "width": 172 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 620, - "left": 203, - "height": 323, - "width": 389 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 183, - "left": 17, - "height": 126, - "width": 223 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 211, - "left": 286, - "height": 112, - "width": 109 - }, - "classifications": [] - }] - }, { - "frameNumber": 74, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 873, - "left": 980, - "height": 207, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 596, - "height": 150, - "width": 173 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 615, - "left": 195, - "height": 323, - "width": 389 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 173, - "left": 10, - "height": 123, - "width": 229 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 209, - "left": 278, - "height": 112, - "width": 107 - }, - "classifications": [] - }] - }, { - "frameNumber": 75, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 878, - "left": 968, - "height": 202, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 588, - "height": 143, - "width": 175 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 616, - "left": 188, - "height": 323, - "width": 389 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 168, - "left": 5, - "height": 113, - "width": 234 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 213, - "left": 276, - "height": 98, - "width": 98 - }, - "classifications": [] - }] - }, { - "frameNumber": 76, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 882, - "left": 961, - "height": 198, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 582, - "height": 143, - "width": 175 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 614, - "left": 185, - "height": 326, - "width": 396 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 168, - "left": 0, - "height": 103, - "width": 237 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 217, - "left": 276, - "height": 86, - "width": 93 - }, - "classifications": [] - }] - }, { - "frameNumber": 77, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 882, - "left": 950, - "height": 198, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 768, - "left": 573, - "height": 174, - "width": 175 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 613, - "left": 182, - "height": 327, - "width": 399 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 161, - "left": 0, - "height": 112, - "width": 232 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 223, - "left": 282, - "height": 55, - "width": 76 - }, - "classifications": [] - }] - }, { - "frameNumber": 78, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 886, - "left": 944, - "height": 194, - "width": 199 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 763, - "left": 567, - "height": 179, - "width": 177 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 613, - "left": 182, - "height": 324, - "width": 399 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 158, - "left": 0, - "height": 118, - "width": 224 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 225, - "left": 301, - "height": 47, - "width": 49 - }, - "classifications": [] - }] - }, { - "frameNumber": 79, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 886, - "left": 936, - "height": 194, - "width": 199 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 760, - "left": 562, - "height": 181, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 611, - "left": 179, - "height": 324, - "width": 399 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 154, - "left": 0, - "height": 179, - "width": 218 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 225, - "left": 309, - "height": 41, - "width": 33 - }, - "classifications": [] - }] - }, { - "frameNumber": 80, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 925, - "height": 189, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 762, - "left": 555, - "height": 181, - "width": 174 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 608, - "left": 177, - "height": 327, - "width": 401 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 144, - "left": 0, - "height": 239, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1352, - "height": 202, - "width": 217 - }, - "classifications": [] - }] - }, { - "frameNumber": 81, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 920, - "height": 189, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 765, - "left": 552, - "height": 172, - "width": 164 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 602, - "left": 179, - "height": 328, - "width": 393 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 140, - "left": 0, - "height": 235, - "width": 208 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 341, - "left": 1347, - "height": 202, - "width": 217 - }, - "classifications": [] - }] - }, { - "frameNumber": 82, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 910, - "height": 189, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 765, - "left": 544, - "height": 173, - "width": 174 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 602, - "left": 179, - "height": 327, - "width": 393 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 132, - "left": 0, - "height": 235, - "width": 208 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 342, - "left": 1336, - "height": 202, - "width": 217 - }, - "classifications": [] - }] - }, { - "frameNumber": 83, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 898, - "height": 184, - "width": 200 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 769, - "left": 541, - "height": 162, - "width": 169 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 598, - "left": 175, - "height": 327, - "width": 393 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 123, - "left": 0, - "height": 238, - "width": 208 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1331, - "height": 203, - "width": 217 - }, - "classifications": [] - }] - }, { - "frameNumber": 84, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 889, - "height": 184, - "width": 203 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 767, - "left": 537, - "height": 153, - "width": 168 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 595, - "left": 171, - "height": 327, - "width": 393 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 117, - "left": 0, - "height": 238, - "width": 208 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1326, - "height": 203, - "width": 217 - }, - "classifications": [] - }] - }, { - "frameNumber": 85, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 879, - "height": 184, - "width": 203 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 531, - "height": 160, - "width": 162 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 585, - "left": 165, - "height": 332, - "width": 400 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 103, - "left": 0, - "height": 272, - "width": 210 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1318, - "height": 204, - "width": 215 - }, - "classifications": [] - }] - }, { - "frameNumber": 86, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 895, - "left": 868, - "height": 185, - "width": 205 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 759, - "left": 526, - "height": 159, - "width": 161 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 584, - "left": 164, - "height": 329, - "width": 400 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 94, - "left": 0, - "height": 274, - "width": 211 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1312, - "height": 204, - "width": 215 - }, - "classifications": [] - }] - }, { - "frameNumber": 87, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 855, - "height": 188, - "width": 206 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 517, - "height": 159, - "width": 161 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 574, - "left": 210, - "height": 334, - "width": 349 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 78, - "left": 0, - "height": 281, - "width": 215 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 341, - "left": 1300, - "height": 204, - "width": 215 - }, - "classifications": [] - }] - }, { - "frameNumber": 88, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 849, - "height": 190, - "width": 206 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 753, - "left": 512, - "height": 163, - "width": 161 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 569, - "left": 207, - "height": 333, - "width": 352 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 71, - "left": 0, - "height": 281, - "width": 220 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1294, - "height": 204, - "width": 215 - }, - "classifications": [] - }] - }, { - "frameNumber": 89, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 839, - "height": 190, - "width": 209 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 746, - "left": 505, - "height": 166, - "width": 170 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 562, - "left": 203, - "height": 333, - "width": 352 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 62, - "left": 0, - "height": 281, - "width": 221 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1288, - "height": 204, - "width": 215 - }, - "classifications": [] - }] - }, { - "frameNumber": 90, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 832, - "height": 188, - "width": 203 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 747, - "left": 498, - "height": 143, - "width": 175 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 557, - "left": 196, - "height": 333, - "width": 352 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 47, - "left": 0, - "height": 283, - "width": 217 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1279, - "height": 205, - "width": 203 - }, - "classifications": [] - }] - }, { - "frameNumber": 91, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 830, - "height": 188, - "width": 197 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 747, - "left": 495, - "height": 141, - "width": 174 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 549, - "left": 193, - "height": 340, - "width": 353 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 38, - "left": 0, - "height": 283, - "width": 217 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 335, - "left": 1272, - "height": 208, - "width": 207 - }, - "classifications": [] - }] - }, { - "frameNumber": 92, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 826, - "height": 190, - "width": 189 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 487, - "height": 146, - "width": 145 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 546, - "left": 187, - "height": 334, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 27, - "left": 0, - "height": 285, - "width": 213 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 334, - "left": 1263, - "height": 208, - "width": 207 - }, - "classifications": [] - }] - }, { - "frameNumber": 93, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 813, - "height": 187, - "width": 196 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 478, - "height": 143, - "width": 179 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 540, - "left": 187, - "height": 343, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 17, - "left": 0, - "height": 292, - "width": 213 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1258, - "height": 208, - "width": 198 - }, - "classifications": [] - }] - }, { - "frameNumber": 94, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 893.5, - "left": 812, - "height": 186.5, - "width": 186 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 735, - "left": 474, - "height": 149, - "width": 177 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 533, - "left": 184, - "height": 343, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 9, - "left": 0, - "height": 292, - "width": 213 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1251, - "height": 208, - "width": 198 - }, - "classifications": [] - }] - }, { - "frameNumber": 95, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 894, - "left": 811, - "height": 186, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 465, - "height": 146, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 534, - "left": 181, - "height": 340, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 293, - "width": 209 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 336, - "left": 1240, - "height": 208, - "width": 192 - }, - "classifications": [] - }] - }, { - "frameNumber": 96, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 898, - "left": 809, - "height": 182, - "width": 171 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 460, - "height": 143, - "width": 181 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 528, - "left": 178, - "height": 340, - "width": 357 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 288, - "width": 210 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 336, - "left": 1234, - "height": 211, - "width": 195 - }, - "classifications": [] - }] - }, { - "frameNumber": 97, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 805, - "height": 184, - "width": 165 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 455, - "height": 138, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 524.5, - "left": 178, - "height": 343.5, - "width": 357.5 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 278, - "width": 213 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1223, - "height": 211, - "width": 195 - }, - "classifications": [] - }] - }, { - "frameNumber": 98, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 800, - "height": 187, - "width": 163 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 741, - "left": 449, - "height": 134, - "width": 176 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 521, - "left": 178, - "height": 347, - "width": 358 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 268, - "width": 211 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1219, - "height": 211, - "width": 195 - }, - "classifications": [] - }] - }, { - "frameNumber": 99, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 795, - "height": 187, - "width": 160 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 449, - "height": 136, - "width": 171 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 515, - "left": 178, - "height": 345, - "width": 359 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 266, - "width": 215 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 339, - "left": 1214, - "height": 211, - "width": 195 - }, - "classifications": [] - }] - }, { - "frameNumber": 100, - "classifications": [], - "objects": [{ - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 898, - "left": 786, - "height": 182, - "width": 158 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 467, - "height": 136, - "width": 146 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 515, - "left": 178, - "height": 345, - "width": 359 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 256, - "width": 217 - }, - "classifications": [] - }, { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1203, - "height": 211, - "width": 195 - }, - "classifications": [] - }] - }], + "Label": [ + { + "frameNumber": 1, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 582, + "left": 1644, + "height": 340, + "width": 212 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 712, + "left": 1256, + "height": 204, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 47, + "left": 155, + "height": 381, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 546, + "height": 263, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 361, + "height": 183, + "width": 207 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 2, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 595, + "left": 1635, + "height": 340, + "width": 212 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 719, + "left": 1246, + "height": 204, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 45, + "left": 148, + "height": 381, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 540, + "height": 262, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 353, + "height": 184, + "width": 209 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 3, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 600, + "left": 1628, + "height": 326, + "width": 212 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1233, + "height": 188, + "width": 332 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 46, + "left": 130, + "height": 381, + "width": 341 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 732, + "left": 536, + "height": 262, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 346, + "height": 183, + "width": 211 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 4, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 604, + "left": 1619, + "height": 322, + "width": 214 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1225, + "height": 180, + "width": 336 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 37, + "left": 123, + "height": 386, + "width": 343 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 732, + "left": 536, + "height": 269, + "width": 288 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 338, + "height": 185, + "width": 216 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 5, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 619, + "left": 1606, + "height": 322, + "width": 214 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 729, + "left": 1208, + "height": 180, + "width": 336 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 36, + "left": 116, + "height": 386, + "width": 343 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 529, + "height": 269, + "width": 288 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 493, + "left": 332, + "height": 185, + "width": 216 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 6, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 1597, + "height": 322, + "width": 214 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 1195, + "height": 180, + "width": 336 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 30, + "left": 108, + "height": 386, + "width": 343 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 734.5, + "left": 522, + "height": 269, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 491, + "left": 326, + "height": 185, + "width": 216 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 7, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 632, + "left": 1586, + "height": 322, + "width": 214 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 1189, + "height": 175, + "width": 323 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 30, + "left": 86, + "height": 367, + "width": 354 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 515, + "height": 269, + "width": 292 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 490, + "left": 316, + "height": 183, + "width": 218 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 8, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 634, + "left": 1582, + "height": 321, + "width": 209 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 751, + "left": 1188, + "height": 170, + "width": 316 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 26, + "left": 78, + "height": 367, + "width": 354 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 500, + "height": 266, + "width": 302 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 488, + "left": 311, + "height": 183, + "width": 218 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 9, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 641, + "left": 1575, + "height": 321, + "width": 209 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 1188, + "height": 168, + "width": 307 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 23, + "left": 63, + "height": 372, + "width": 362 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 500, + "height": 270, + "width": 297 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 488, + "left": 305, + "height": 182, + "width": 219 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 10, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 648, + "left": 1563, + "height": 315, + "width": 203 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 1172, + "height": 172, + "width": 309 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 14, + "left": 48, + "height": 371, + "width": 366 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 493, + "height": 271, + "width": 304 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 486, + "left": 292, + "height": 184, + "width": 224 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 11, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 1555, + "height": 317, + "width": 208 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 1169, + "height": 174, + "width": 294 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 11, + "left": 47, + "height": 374, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 484, + "height": 271, + "width": 304 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 485, + "left": 287, + "height": 184, + "width": 224 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 12, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 1545, + "height": 317, + "width": 204 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 1162, + "height": 168, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 34, + "height": 374, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 476, + "height": 271, + "width": 304 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 479, + "left": 278, + "height": 184, + "width": 224 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 13, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 663, + "left": 1538, + "height": 317, + "width": 204 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 749, + "left": 1154, + "height": 173, + "width": 289 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 27, + "height": 374, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 473, + "height": 271, + "width": 304 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 476, + "left": 271, + "height": 183, + "width": 229 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 14, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 666, + "left": 1531, + "height": 314, + "width": 211 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 748, + "left": 1147, + "height": 176, + "width": 283 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 23, + "height": 312, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 470, + "height": 271, + "width": 304 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 470, + "left": 264, + "height": 187, + "width": 231 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 15, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 670, + "left": 1519, + "height": 316, + "width": 207 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 742, + "left": 1136, + "height": 187, + "width": 272 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 23, + "height": 281, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 457, + "height": 278, + "width": 312 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 464, + "left": 254, + "height": 193, + "width": 235 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 16, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 674, + "left": 1512, + "height": 311, + "width": 204 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 1129, + "height": 190, + "width": 279 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 19, + "height": 276, + "width": 356 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 457, + "height": 277, + "width": 306 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 457, + "left": 245, + "height": 189, + "width": 238 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 17, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 678, + "left": 1502, + "height": 310, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1118, + "height": 198, + "width": 267 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 271, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 725, + "left": 447, + "height": 277, + "width": 306 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 453, + "left": 236, + "height": 189, + "width": 238 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 18, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 679, + "left": 1496, + "height": 310, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1110, + "height": 203, + "width": 262 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 0, + "left": 0, + "height": 265.5, + "width": 360 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 725, + "left": 438, + "height": 276, + "width": 315 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 450, + "left": 227, + "height": 191, + "width": 244 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 19, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 685, + "left": 1489, + "height": 317, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 730, + "left": 1099, + "height": 206, + "width": 273 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 260, + "width": 353 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 438, + "height": 271, + "width": 307 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 449, + "left": 222, + "height": 183, + "width": 244 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 20, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 689, + "left": 1477, + "height": 317, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 1086, + "height": 213, + "width": 260 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 258, + "width": 345 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 721, + "left": 431, + "height": 271, + "width": 308 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 448, + "left": 217, + "height": 177, + "width": 244 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 21, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 690, + "left": 1470, + "height": 317, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1077, + "height": 213, + "width": 260 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 259, + "width": 335 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 423, + "height": 271, + "width": 308 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 446, + "left": 212, + "height": 177, + "width": 244 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 22, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 697, + "left": 1458, + "height": 317, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1065, + "height": 213, + "width": 260 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 227, + "width": 313 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 420, + "height": 250, + "width": 302 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 446, + "left": 212, + "height": 164, + "width": 236 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 23, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 701, + "left": 1449, + "height": 317, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 727, + "left": 1055, + "height": 219, + "width": 253 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 214, + "width": 307 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 417, + "height": 250, + "width": 302 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 432, + "left": 190, + "height": 147, + "width": 255 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 24, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 1447, + "height": 321, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 1049, + "height": 229, + "width": 250 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 202, + "width": 282 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 408, + "height": 235, + "width": 308 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 448, + "left": 209, + "height": 150, + "width": 228 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 25, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 708, + "left": 1433, + "height": 321, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1035, + "height": 229, + "width": 251 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 198, + "width": 272 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 759, + "left": 399, + "height": 234, + "width": 317 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 424, + "left": 170, + "height": 148, + "width": 262 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 26, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 714, + "left": 1425, + "height": 313, + "width": 194 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 1027, + "height": 240, + "width": 248 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 190, + "width": 272 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 392, + "height": 227, + "width": 322 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 413, + "left": 163, + "height": 152, + "width": 230 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 27, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 719, + "left": 1413, + "height": 313, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 1018, + "height": 235, + "width": 238 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 208, + "width": 284 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 754, + "left": 384.5, + "height": 228.5, + "width": 328.5 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 409, + "left": 151, + "height": 178, + "width": 268 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 28, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1408, + "height": 313, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 735, + "left": 1011, + "height": 217, + "width": 237 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 206, + "width": 281 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 377, + "height": 230, + "width": 335 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 409, + "left": 148, + "height": 178, + "width": 268 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 29, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 1398, + "height": 313, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 1006, + "height": 205, + "width": 233 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 200, + "width": 274 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 370, + "height": 232, + "width": 342 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 401, + "left": 138, + "height": 181, + "width": 275 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 30, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1389, + "height": 313, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 751, + "left": 993, + "height": 182, + "width": 230 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 191, + "width": 261 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 745, + "left": 368, + "height": 232, + "width": 342 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 397, + "left": 132, + "height": 181, + "width": 275 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 31, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1381, + "height": 308, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 988, + "height": 181, + "width": 216 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 190, + "width": 258 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 368, + "height": 243, + "width": 341 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 394, + "left": 125, + "height": 181, + "width": 275 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 32, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 1369, + "height": 308, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 769, + "left": 979, + "height": 167, + "width": 204 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 181, + "width": 247 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 367, + "height": 251, + "width": 341 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 387, + "left": 116, + "height": 182, + "width": 280 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 33, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 1361, + "height": 308, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 774, + "left": 973, + "height": 163, + "width": 199 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 176, + "width": 239 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 720, + "left": 368, + "height": 261, + "width": 340 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 383, + "left": 106, + "height": 180, + "width": 286 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 34, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 1353, + "height": 308, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 778, + "left": 967, + "height": 162, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 171, + "width": 235 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 718, + "left": 364, + "height": 257, + "width": 344 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 379, + "left": 100, + "height": 183, + "width": 287 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 35, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 749, + "left": 1343, + "height": 308, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 795, + "left": 957, + "height": 148, + "width": 178 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 160, + "width": 225 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 711, + "left": 363, + "height": 256, + "width": 343 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 375, + "left": 93.5, + "height": 187, + "width": 289.5 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 36, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 752, + "left": 1337, + "height": 309, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 796, + "left": 948, + "height": 149, + "width": 185 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 150, + "width": 216 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 710, + "left": 365, + "height": 269, + "width": 340 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 371, + "left": 87, + "height": 191, + "width": 292 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 37, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 1324, + "height": 302, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 794, + "left": 935, + "height": 153, + "width": 177 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 131, + "width": 206 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 704, + "left": 360, + "height": 275, + "width": 342 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 365, + "left": 76, + "height": 194, + "width": 297 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 38, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 763, + "left": 1318, + "height": 302, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 789, + "left": 928, + "height": 160, + "width": 174 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 106, + "width": 199 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 702, + "left": 357, + "height": 277, + "width": 341 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 363, + "left": 70, + "height": 199, + "width": 300 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 39, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 1310, + "height": 302, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 786, + "left": 918, + "height": 164, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 38, + "width": 134 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 695, + "left": 357, + "height": 282, + "width": 340 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 359, + "left": 64, + "height": 200, + "width": 302 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 40, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 770, + "left": 1299, + "height": 302, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 775, + "left": 905, + "height": 177, + "width": 177 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 16, + "width": 111 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 694, + "left": 354, + "height": 282, + "width": 338 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 353, + "left": 56, + "height": 203, + "width": 305 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 41, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 772, + "left": 1289, + "height": 302, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 896, + "height": 185, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 688.5, + "left": 351.5, + "height": 287, + "width": 338.5 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 350, + "left": 51, + "height": 203, + "width": 306 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 321, + "left": 569, + "height": 125, + "width": 109 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 42, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 775, + "left": 1281, + "height": 297, + "width": 188 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 884, + "height": 196, + "width": 175 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 683, + "left": 349, + "height": 292, + "width": 339 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 342, + "left": 41, + "height": 204, + "width": 310 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 317, + "left": 559.5, + "height": 126, + "width": 111 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 43, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 778, + "left": 1273, + "height": 297, + "width": 188 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 748, + "left": 875, + "height": 202, + "width": 152 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 682, + "left": 346, + "height": 292, + "width": 339 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 335, + "left": 37, + "height": 204, + "width": 310 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 313, + "left": 550, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 44, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 779, + "left": 1266, + "height": 293, + "width": 188 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 741, + "left": 865, + "height": 211, + "width": 158 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 681, + "left": 345, + "height": 292, + "width": 339 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 331, + "left": 33, + "height": 204, + "width": 310 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 309, + "left": 543, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 45, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 785, + "left": 1255, + "height": 293, + "width": 188 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 734, + "left": 855.5, + "height": 217.5, + "width": 160 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 672, + "left": 340, + "height": 296, + "width": 339 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 322, + "left": 28, + "height": 211, + "width": 311 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 303, + "left": 532, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 46, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 784, + "left": 1245, + "height": 293, + "width": 188 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 727, + "left": 846, + "height": 224, + "width": 162 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 669, + "left": 344, + "height": 297, + "width": 333 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 314, + "left": 23, + "height": 211, + "width": 311 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 298, + "left": 526, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 47, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 787, + "left": 1234, + "height": 290, + "width": 186 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 832, + "height": 224, + "width": 165 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 668, + "left": 339, + "height": 297, + "width": 333 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 306, + "left": 12, + "height": 211, + "width": 315 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 291, + "left": 514, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 48, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 790, + "left": 1227, + "height": 286, + "width": 187 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 714, + "left": 824, + "height": 235, + "width": 167 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 667, + "left": 335, + "height": 297, + "width": 333 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 301, + "left": 7, + "height": 211, + "width": 315 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 289, + "left": 506, + "height": 127, + "width": 113 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 49, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 792, + "left": 1216, + "height": 286, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 710, + "left": 815, + "height": 238, + "width": 167 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 664, + "left": 337, + "height": 297, + "width": 327 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 298, + "left": 0, + "height": 214, + "width": 319 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 285, + "left": 498, + "height": 127, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 50, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 797, + "left": 1205, + "height": 283, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 815, + "height": 239, + "width": 157 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 658, + "left": 334, + "height": 302, + "width": 327 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 290, + "left": 0, + "height": 217, + "width": 312 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 281, + "left": 485, + "height": 127, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 51, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 797, + "left": 1197, + "height": 283, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 812, + "height": 240, + "width": 157 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 328, + "height": 302, + "width": 327 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 284, + "left": 0, + "height": 223, + "width": 310 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 277, + "left": 478, + "height": 127, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 52, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 801, + "left": 1183, + "height": 279, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 802, + "height": 243, + "width": 150 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 322, + "height": 299, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 279, + "left": 0, + "height": 220, + "width": 302 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 271, + "left": 465, + "height": 129, + "width": 117 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 53, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 807, + "left": 1177, + "height": 273, + "width": 191 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 802, + "height": 243, + "width": 144 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 659, + "left": 316, + "height": 297, + "width": 333 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 274, + "left": 0, + "height": 225, + "width": 298 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 270, + "left": 456, + "height": 129, + "width": 117 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 54, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 807, + "left": 1167, + "height": 273, + "width": 191 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 704, + "left": 792, + "height": 247, + "width": 145 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 312, + "height": 306, + "width": 332 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 270, + "left": 0, + "height": 229, + "width": 295 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 266, + "left": 448, + "height": 129, + "width": 117 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 55, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 1156, + "height": 267, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 706, + "left": 783, + "height": 247, + "width": 145 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 310, + "height": 304, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 260, + "left": 0, + "height": 231, + "width": 290 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 261, + "left": 435, + "height": 129, + "width": 118 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 56, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 1148, + "height": 267, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 706, + "left": 784, + "height": 248, + "width": 147 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 308, + "height": 304, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 257, + "left": 0, + "height": 234, + "width": 286 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 260, + "left": 428, + "height": 129, + "width": 118 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 57, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 819, + "left": 1134, + "height": 261, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 776, + "height": 248, + "width": 146 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 647, + "left": 303, + "height": 304, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 250, + "left": 0, + "height": 235, + "width": 283 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 255, + "left": 415, + "height": 128, + "width": 120 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 58, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 822, + "left": 1127, + "height": 258, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 775, + "height": 250, + "width": 138 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 648, + "left": 300, + "height": 304, + "width": 330 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 246, + "left": 0, + "height": 236, + "width": 279 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 250, + "left": 406, + "height": 128, + "width": 120 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 59, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 825, + "left": 1120, + "height": 255, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 709.5, + "left": 780, + "height": 249, + "width": 124 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 645, + "left": 297.5, + "height": 306.5, + "width": 328 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 244, + "left": 11, + "height": 238, + "width": 265 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 248, + "left": 396, + "height": 127.5, + "width": 122 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 60, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 828, + "left": 1108, + "height": 252, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 712, + "left": 785, + "height": 248, + "width": 110 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 642, + "left": 295, + "height": 309, + "width": 326 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 238, + "left": 24, + "height": 244, + "width": 248 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 246, + "left": 386, + "height": 127, + "width": 124 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 61, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 832, + "left": 1099, + "height": 248, + "width": 191 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 716, + "left": 790, + "height": 241, + "width": 98 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 640, + "left": 279.5, + "height": 310, + "width": 340 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 233, + "left": 41, + "height": 243, + "width": 227 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 243, + "left": 379, + "height": 128, + "width": 123 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 62, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 836, + "left": 1088, + "height": 244, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 894, + "left": 777, + "height": 63, + "width": 99 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 638, + "left": 264, + "height": 311, + "width": 354 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 227, + "left": 43, + "height": 234, + "width": 221 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 238, + "left": 367, + "height": 128, + "width": 123 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 63, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 840, + "left": 1081, + "height": 240, + "width": 191 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 776, + "height": 60, + "width": 94 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 638, + "left": 256, + "height": 312, + "width": 359 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 226, + "left": 38, + "height": 225, + "width": 226 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 235, + "left": 361, + "height": 128, + "width": 123 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 64, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 843, + "left": 1074, + "height": 237, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 860, + "left": 723, + "height": 85.5, + "width": 131 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 636.5, + "left": 250, + "height": 313, + "width": 363 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 222, + "left": 31, + "height": 222, + "width": 229 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 230, + "left": 361, + "height": 131, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 65, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 847, + "left": 1064, + "height": 233, + "width": 190 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 828, + "left": 670, + "height": 111, + "width": 168 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 635, + "left": 244, + "height": 314, + "width": 367 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 216, + "left": 29, + "height": 190, + "width": 228 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 227, + "left": 350, + "height": 131, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 66, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1054, + "height": 228, + "width": 192 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 662, + "height": 116, + "width": 169 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 634.5, + "left": 239, + "height": 313, + "width": 369 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 214, + "left": 29, + "height": 163, + "width": 227 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 222, + "left": 343, + "height": 131, + "width": 115 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 67, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1042, + "height": 228, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 808, + "left": 651, + "height": 122, + "width": 166 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 634, + "left": 234, + "height": 312, + "width": 371 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 209, + "left": 23, + "height": 161, + "width": 229 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 220, + "left": 337, + "height": 130, + "width": 110 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 68, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1035, + "height": 228, + "width": 193 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 808, + "left": 651, + "height": 122, + "width": 156 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 224, + "height": 322, + "width": 377 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 203, + "left": 24, + "height": 163, + "width": 227 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 217, + "left": 329, + "height": 130, + "width": 108 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 69, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 857, + "left": 1028, + "height": 223, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 802, + "left": 637, + "height": 127, + "width": 158 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 623, + "left": 220.667, + "height": 321.667, + "width": 379.333 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 203, + "left": 19, + "height": 153, + "width": 231 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 213, + "left": 325, + "height": 130, + "width": 108 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 70, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 864, + "left": 1016, + "height": 216, + "width": 198 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 802, + "left": 629.5, + "height": 129.5, + "width": 153 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 623, + "left": 217.333, + "height": 321.333, + "width": 381.667 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 202.5, + "left": 19.5, + "height": 142.5, + "width": 228 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 212, + "left": 315, + "height": 124.5, + "width": 108 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 71, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 864, + "left": 1009, + "height": 216, + "width": 198 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 802, + "left": 622, + "height": 132, + "width": 148 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 214, + "height": 321, + "width": 384 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 202, + "left": 20, + "height": 132, + "width": 225 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 211, + "left": 305, + "height": 119, + "width": 108 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 72, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 868, + "left": 994, + "height": 212, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 798, + "left": 610, + "height": 138, + "width": 165 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 620, + "left": 203, + "height": 323, + "width": 388 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 189, + "left": 16, + "height": 137, + "width": 227 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 212, + "left": 294, + "height": 114, + "width": 108 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 73, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 873, + "left": 987, + "height": 207, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 787, + "left": 603, + "height": 151, + "width": 172 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 620, + "left": 203, + "height": 323, + "width": 389 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 183, + "left": 17, + "height": 126, + "width": 223 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 211, + "left": 286, + "height": 112, + "width": 109 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 74, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 873, + "left": 980, + "height": 207, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 596, + "height": 150, + "width": 173 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 615, + "left": 195, + "height": 323, + "width": 389 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 173, + "left": 10, + "height": 123, + "width": 229 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 209, + "left": 278, + "height": 112, + "width": 107 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 75, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 878, + "left": 968, + "height": 202, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 588, + "height": 143, + "width": 175 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 616, + "left": 188, + "height": 323, + "width": 389 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 168, + "left": 5, + "height": 113, + "width": 234 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 213, + "left": 276, + "height": 98, + "width": 98 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 76, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 882, + "left": 961, + "height": 198, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 582, + "height": 143, + "width": 175 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 614, + "left": 185, + "height": 326, + "width": 396 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 168, + "left": 0, + "height": 103, + "width": 237 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 217, + "left": 276, + "height": 86, + "width": 93 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 77, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 882, + "left": 950, + "height": 198, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 768, + "left": 573, + "height": 174, + "width": 175 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 613, + "left": 182, + "height": 327, + "width": 399 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 161, + "left": 0, + "height": 112, + "width": 232 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 223, + "left": 282, + "height": 55, + "width": 76 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 78, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 886, + "left": 944, + "height": 194, + "width": 199 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 763, + "left": 567, + "height": 179, + "width": 177 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 613, + "left": 182, + "height": 324, + "width": 399 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 158, + "left": 0, + "height": 118, + "width": 224 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 225, + "left": 301, + "height": 47, + "width": 49 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 79, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 886, + "left": 936, + "height": 194, + "width": 199 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 760, + "left": 562, + "height": 181, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 611, + "left": 179, + "height": 324, + "width": 399 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 154, + "left": 0, + "height": 179, + "width": 218 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 225, + "left": 309, + "height": 41, + "width": 33 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 80, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 925, + "height": 189, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 762, + "left": 555, + "height": 181, + "width": 174 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 608, + "left": 177, + "height": 327, + "width": 401 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 144, + "left": 0, + "height": 239, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1352, + "height": 202, + "width": 217 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 81, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 920, + "height": 189, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 765, + "left": 552, + "height": 172, + "width": 164 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 602, + "left": 179, + "height": 328, + "width": 393 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 140, + "left": 0, + "height": 235, + "width": 208 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 341, + "left": 1347, + "height": 202, + "width": 217 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 82, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 910, + "height": 189, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 765, + "left": 544, + "height": 173, + "width": 174 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 602, + "left": 179, + "height": 327, + "width": 393 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 132, + "left": 0, + "height": 235, + "width": 208 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 342, + "left": 1336, + "height": 202, + "width": 217 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 83, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 898, + "height": 184, + "width": 200 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 769, + "left": 541, + "height": 162, + "width": 169 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 598, + "left": 175, + "height": 327, + "width": 393 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 123, + "left": 0, + "height": 238, + "width": 208 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1331, + "height": 203, + "width": 217 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 84, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 889, + "height": 184, + "width": 203 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 767, + "left": 537, + "height": 153, + "width": 168 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 595, + "left": 171, + "height": 327, + "width": 393 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 117, + "left": 0, + "height": 238, + "width": 208 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1326, + "height": 203, + "width": 217 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 85, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 879, + "height": 184, + "width": 203 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 531, + "height": 160, + "width": 162 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 585, + "left": 165, + "height": 332, + "width": 400 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 103, + "left": 0, + "height": 272, + "width": 210 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1318, + "height": 204, + "width": 215 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 86, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 895, + "left": 868, + "height": 185, + "width": 205 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 759, + "left": 526, + "height": 159, + "width": 161 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 584, + "left": 164, + "height": 329, + "width": 400 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 94, + "left": 0, + "height": 274, + "width": 211 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1312, + "height": 204, + "width": 215 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 87, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 855, + "height": 188, + "width": 206 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 517, + "height": 159, + "width": 161 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 574, + "left": 210, + "height": 334, + "width": 349 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 78, + "left": 0, + "height": 281, + "width": 215 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 341, + "left": 1300, + "height": 204, + "width": 215 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 88, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 849, + "height": 190, + "width": 206 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 753, + "left": 512, + "height": 163, + "width": 161 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 569, + "left": 207, + "height": 333, + "width": 352 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 71, + "left": 0, + "height": 281, + "width": 220 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1294, + "height": 204, + "width": 215 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 89, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 839, + "height": 190, + "width": 209 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 746, + "left": 505, + "height": 166, + "width": 170 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 562, + "left": 203, + "height": 333, + "width": 352 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 62, + "left": 0, + "height": 281, + "width": 221 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1288, + "height": 204, + "width": 215 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 90, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 832, + "height": 188, + "width": 203 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 747, + "left": 498, + "height": 143, + "width": 175 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 557, + "left": 196, + "height": 333, + "width": 352 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 47, + "left": 0, + "height": 283, + "width": 217 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1279, + "height": 205, + "width": 203 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 91, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 830, + "height": 188, + "width": 197 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 747, + "left": 495, + "height": 141, + "width": 174 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 549, + "left": 193, + "height": 340, + "width": 353 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 38, + "left": 0, + "height": 283, + "width": 217 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 335, + "left": 1272, + "height": 208, + "width": 207 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 92, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 826, + "height": 190, + "width": 189 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 487, + "height": 146, + "width": 145 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 546, + "left": 187, + "height": 334, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 27, + "left": 0, + "height": 285, + "width": 213 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 334, + "left": 1263, + "height": 208, + "width": 207 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 93, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 813, + "height": 187, + "width": 196 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 478, + "height": 143, + "width": 179 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 540, + "left": 187, + "height": 343, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 17, + "left": 0, + "height": 292, + "width": 213 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1258, + "height": 208, + "width": 198 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 94, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 893.5, + "left": 812, + "height": 186.5, + "width": 186 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 735, + "left": 474, + "height": 149, + "width": 177 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 533, + "left": 184, + "height": 343, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 9, + "left": 0, + "height": 292, + "width": 213 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1251, + "height": 208, + "width": 198 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 95, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 894, + "left": 811, + "height": 186, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 465, + "height": 146, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 534, + "left": 181, + "height": 340, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 293, + "width": 209 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 336, + "left": 1240, + "height": 208, + "width": 192 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 96, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 898, + "left": 809, + "height": 182, + "width": 171 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 460, + "height": 143, + "width": 181 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 528, + "left": 178, + "height": 340, + "width": 357 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 288, + "width": 210 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 336, + "left": 1234, + "height": 211, + "width": 195 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 97, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 805, + "height": 184, + "width": 165 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 455, + "height": 138, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 524.5, + "left": 178, + "height": 343.5, + "width": 357.5 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 278, + "width": 213 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1223, + "height": 211, + "width": 195 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 98, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 800, + "height": 187, + "width": 163 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 741, + "left": 449, + "height": 134, + "width": 176 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 521, + "left": 178, + "height": 347, + "width": 358 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 268, + "width": 211 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1219, + "height": 211, + "width": 195 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 99, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 795, + "height": 187, + "width": 160 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 449, + "height": 136, + "width": 171 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 515, + "left": 178, + "height": 345, + "width": 359 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 266, + "width": 215 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 339, + "left": 1214, + "height": 211, + "width": 195 + }, + "classifications": [] + } + ] + }, + { + "frameNumber": 100, + "classifications": [], + "objects": [ + { + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 898, + "left": 786, + "height": 182, + "width": 158 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 467, + "height": 136, + "width": 146 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 515, + "left": 178, + "height": 345, + "width": 359 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 256, + "width": 217 + }, + "classifications": [] + }, + { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1203, + "height": 211, + "width": 195 + }, + "classifications": [] + } + ] + } + ], "Created By": "msokoloff+11@labelbox.com", "Project Name": "Sample Video Project", "Created At": "2021-06-25T22:38:27.000Z", diff --git a/libs/labelbox/tests/data/serialization/labelbox_v1/test_document.py b/libs/labelbox/tests/data/serialization/labelbox_v1/test_document.py index a5a0f611e..89b2e6c07 100644 --- a/libs/labelbox/tests/data/serialization/labelbox_v1/test_document.py +++ b/libs/labelbox/tests/data/serialization/labelbox_v1/test_document.py @@ -2,6 +2,7 @@ from typing import Dict, Any from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter +import pytest IGNORE_KEYS = [ "Data Split", "media_type", "DataRow Metadata", "Media Attributes" @@ -16,7 +17,7 @@ def round_dict(data: Dict[str, Any]) -> Dict[str, Any]: data[key] = round_dict(data[key]) return data - +@pytest.mark.skip() def test_pdf(): """ Tests an export from a pdf document with only bounding boxes diff --git a/libs/labelbox/tests/data/serialization/labelbox_v1/test_image.py b/libs/labelbox/tests/data/serialization/labelbox_v1/test_image.py index 546c97f64..8be9d7335 100644 --- a/libs/labelbox/tests/data/serialization/labelbox_v1/test_image.py +++ b/libs/labelbox/tests/data/serialization/labelbox_v1/test_image.py @@ -5,6 +5,7 @@ from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter +@pytest.mark.skip() @pytest.mark.parametrize("file_path", [ 'tests/data/assets/labelbox_v1/highly_nested_image.json', 'tests/data/assets/labelbox_v1/image_export.json' diff --git a/libs/labelbox/tests/data/serialization/labelbox_v1/test_text.py b/libs/labelbox/tests/data/serialization/labelbox_v1/test_text.py index bd28a6c04..446e760af 100644 --- a/libs/labelbox/tests/data/serialization/labelbox_v1/test_text.py +++ b/libs/labelbox/tests/data/serialization/labelbox_v1/test_text.py @@ -1,8 +1,9 @@ import json from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter +import pytest - +@pytest.mark.skip() def test_text(): with open('tests/data/assets/labelbox_v1/text_export.json', 'r') as file: payload = json.load(file) diff --git a/libs/labelbox/tests/data/serialization/labelbox_v1/test_tiled_image.py b/libs/labelbox/tests/data/serialization/labelbox_v1/test_tiled_image.py index e5afce4ef..df7e59405 100644 --- a/libs/labelbox/tests/data/serialization/labelbox_v1/test_tiled_image.py +++ b/libs/labelbox/tests/data/serialization/labelbox_v1/test_tiled_image.py @@ -9,7 +9,7 @@ from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter from labelbox.schema.bulk_import_request import Bbox - +@pytest.mark.skip() @pytest.mark.parametrize( "file_path", ['tests/data/assets/labelbox_v1/tiled_image_export.json']) def test_image(file_path): diff --git a/libs/labelbox/tests/data/serialization/labelbox_v1/test_unknown_media.py b/libs/labelbox/tests/data/serialization/labelbox_v1/test_unknown_media.py index 4607d7be3..c4a32b667 100644 --- a/libs/labelbox/tests/data/serialization/labelbox_v1/test_unknown_media.py +++ b/libs/labelbox/tests/data/serialization/labelbox_v1/test_unknown_media.py @@ -4,7 +4,7 @@ from labelbox.data.serialization.labelbox_v1.converter import LBV1Converter - +@pytest.mark.skip() def test_image(): file_path = 'tests/data/assets/labelbox_v1/unkown_media_type_export.json' with open(file_path, 'r') as file: From 83fcf4738c42a510f5dcf58e3e1cf856785ff405 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Mon, 22 Jul 2024 23:19:46 -0500 Subject: [PATCH 16/34] revert mistake --- libs/labelbox/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/labelbox/pyproject.toml b/libs/labelbox/pyproject.toml index ef8f595d2..35865e6f5 100644 --- a/libs/labelbox/pyproject.toml +++ b/libs/labelbox/pyproject.toml @@ -86,7 +86,7 @@ unit = "pytest tests/unit" # SERVICE_API_KEY=${SERVICE_API_KEY} \ # LABELBOX_TEST_BASE_URL="http://host.docker.internal:8080" \ integration = { cmd = "pytest tests/integration" } -data = { cmd = "pytest tests/data/serialization/coco" } +data = { cmd = "pytest tests/data" } yapf-lint = "yapf tests src -i --verbose --recursive --parallel --style \"google\"" mypy-lint = "mypy src --pretty --show-error-codes --non-interactive --install-types" lint = { chain = ["yapf-lint", "mypy-lint"] } From 24e8d5f57c92d0993a32869aad306f9e3707dbcf Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Mon, 22 Jul 2024 23:31:29 -0500 Subject: [PATCH 17/34] fixed final bad test --- libs/labelbox/src/labelbox/schema/data_row_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 0a0b25ff2..7066f254a 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -120,7 +120,7 @@ def serialize_model(self, handler): class _UpsertCustomMetadataSchemaEnumOptionInput(_CamelCaseMixin): - id: Optional[SchemaId] + id: Optional[SchemaId] = None name: Annotated[str, StringConstraints(strip_whitespace=True, min_length=1, max_length=100)] From 607fc9fb9cab924c574b8707928d40e486a5155e Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 00:23:19 -0500 Subject: [PATCH 18/34] cleaned pr up --- .../classification/classification.py | 27 +- .../data/generic_data_row_data.py | 1 + .../data/annotation_types/data/raster.py | 14 +- .../data/annotation_types/data/text.py | 12 +- .../data/annotation_types/data/tiled_image.py | 8 +- .../data/annotation_types/data/video.py | 14 +- .../metrics/confusion_matrix.py | 4 +- .../data/annotation_types/metrics/scalar.py | 7 - .../data/annotation_types/ner/text_entity.py | 8 +- .../labelbox/data/annotation_types/video.py | 6 +- libs/labelbox/src/labelbox/data/mixins.py | 11 - .../data/serialization/ndjson/base.py | 21 +- .../serialization/ndjson/classification.py | 8 +- .../data/serialization/ndjson/objects.py | 2 +- .../src/labelbox/pydantic_serializers.py | 31 - .../labelbox/schema/bulk_import_request.py | 6 +- .../src/labelbox/schema/consensus_settings.py | 1 - .../src/labelbox/schema/data_row_metadata.py | 20 +- .../schema/send_to_annotate_params.py | 8 +- .../data/assets/labelbox_v1/video_export.json | 15503 ++++++++-------- .../data/assets/ndjson/video_import.json | 362 +- 21 files changed, 7614 insertions(+), 8460 deletions(-) delete mode 100644 libs/labelbox/src/labelbox/pydantic_serializers.py diff --git a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py index 80c515b48..23c4c848a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/classification/classification.py @@ -3,14 +3,8 @@ from labelbox.data.mixins import ConfidenceMixin, CustomMetricsMixin -try: - from typing import Literal -except: - from typing_extensions import Literal - -from pydantic import BaseModel, model_serializer +from pydantic import BaseModel from ..feature import FeatureSchema -from labelbox.pydantic_serializers import _feature_serializer class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): @@ -28,9 +22,6 @@ class ClassificationAnswer(FeatureSchema, ConfidenceMixin, CustomMetricsMixin): keyframe: Optional[bool] = None classifications: Optional[List['ClassificationAnnotation']] = None - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ A classification with only one selected option allowed @@ -39,10 +30,6 @@ class Radio(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ answer: ClassificationAnswer - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) class Checklist(ConfidenceMixin, BaseModel): @@ -52,10 +39,6 @@ class Checklist(ConfidenceMixin, BaseModel): """ answer: List[ClassificationAnswer] - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel): @@ -65,10 +48,6 @@ class Text(ConfidenceMixin, CustomMetricsMixin, BaseModel): """ answer: str - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, @@ -90,7 +69,3 @@ class ClassificationAnnotation(BaseAnnotation, ConfidenceMixin, value: Union[Text, Checklist, Radio] message_id: Optional[str] = None - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py index 58eb07b9e..6a73519c1 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/generic_data_row_data.py @@ -15,6 +15,7 @@ def create_url(self, signer: Callable[[bytes], str]) -> Optional[str]: return self.url @model_validator(mode="before") + @classmethod def validate_one_datarow_key_present(cls, data): keys = ['external_id', 'global_key', 'uid'] count = sum([key in data for key in keys]) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index 5225ca37a..15ae0aa42 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -160,12 +160,12 @@ def create_url(self, signer: Callable[[bytes], str]) -> str: @model_validator(mode="after") def validate_args(cls, values): - file_path = values.file_path - im_bytes = values.im_bytes - url = values.url - arr = values.arr - uid = values.uid - global_key = values.global_key + file_path = cls.file_path + im_bytes = cls.im_bytes + url = cls.url + arr = cls.arr + uid = cls.uid + global_key = cls.global_key if uid == file_path == im_bytes == url == global_key == None and arr is None: raise ValueError( "One of `file_path`, `im_bytes`, `url`, `uid`, `global_key` or `arr` required." @@ -179,7 +179,7 @@ def validate_args(cls, values): raise ValueError( "unsupported image format. Must be 3D ([H,W,C])." f"Use {cls.__name__}.from_2D_arr to construct from 2D") - return values + return cls def __repr__(self) -> str: symbol_or_none = lambda data: '...' if data is not None else None diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py index 1de158be5..ed57dfefa 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py @@ -93,16 +93,16 @@ def create_url(self, signer: Callable[[bytes], str]) -> None: @model_validator(mode="after") def validate_date(cls, values): - file_path = values.file_path - text = values.text - url = values.url - uid = values.uid - global_key = values.global_key + file_path = cls.file_path + text = cls.text + url = cls.url + uid = cls.uid + global_key = cls.global_key if uid == file_path == text == url == global_key == None: raise ValueError( "One of `file_path`, `text`, `uid`, `global_key` or `url` required." ) - return values + return cls def __repr__(self) -> str: return f"TextData(file_path={self.file_path}," \ diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py index d009a468d..d06f4fc09 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py @@ -67,9 +67,9 @@ def validate_bounds_not_equal(cls, bounds): #validate bounds are within lat,lng range if they are EPSG4326 @model_validator(mode="after") - def validate_bounds_lat_lng(cls, values): - epsg = values.epsg - bounds = values.bounds + def validate_bounds_lat_lng(cls): + epsg = cls.epsg + bounds = cls.bounds if epsg == EPSG.EPSG4326: for bound in bounds: @@ -79,7 +79,7 @@ def validate_bounds_lat_lng(cls, values): raise ValueError(f"Invalid lat/lng bounds. Found {bounds}. " f"lat must be in {VALID_LAT_RANGE}. " f"lng must be in {VALID_LNG_RANGE}.") - return values + return cls class TileLayer(BaseModel): diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py index 3edb975fa..ba74bd4f0 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py @@ -151,18 +151,18 @@ def frames_to_video(self, return file_path @model_validator(mode="after") - def validate_data(cls, values): - file_path = values.file_path - url = values.url - frames = values.frames - uid = values.uid - global_key = values.global_key + def validate_data(cls): + file_path = cls.file_path + url = cls.url + frames = cls.frames + uid = cls.uid + global_key = cls.global_key if uid == file_path == frames == url == global_key == None: raise ValueError( "One of `file_path`, `frames`, `uid`, `global_key` or `url` required." ) - return values + return cls def __repr__(self) -> str: return f"VideoData(file_path={self.file_path}," \ diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py index 3e4991a3a..4a346b8f4 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/confusion_matrix.py @@ -1,7 +1,7 @@ from enum import Enum from typing import Optional, Tuple, Dict, Union -from pydantic import conint +from pydantic import conint, Field from .base import ConfidenceValue, BaseMetric from typing import Literal @@ -31,4 +31,4 @@ class ConfusionMatrixMetric(BaseMetric): metric_name: str value: Union[ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue] - aggregation: Optional[ConfusionMatrixAggregation] = ConfusionMatrixAggregation.CONFUSION_MATRIX + aggregation: Optional[ConfusionMatrixAggregation] = ConfusionMatrixAggregation.CONFUSION_MATRIX diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 8c1ea5216..04279892a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -42,10 +42,3 @@ def validate_metric_name(cls, name: Union[str, None]): raise ValueError(f"`{clean_name}` is a reserved metric name. " "Please provide another value for `metric_name`.") return name - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - res = handler(self) - if res.get('metric_name') is None: - res.pop('aggregation') - return res diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py index 84c4e66f2..9db944312 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py @@ -11,9 +11,9 @@ class TextEntity(BaseModel): @model_validator(mode="after") def validate_start_end(cls, values): - if hasattr(values, 'start') and hasattr(values, 'end'): - if (isinstance(values.start, int) and - values.start > values.end): + if hasattr(cls, 'start') and hasattr(cls, 'end'): + if (isinstance(cls.start, int) and + cls.start > cls.end): raise ValueError( "Location end must be greater or equal to start") - return values + return cls diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index e82aa89fa..8b06949e9 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -97,11 +97,11 @@ class MaskFrame(_CamelCaseMixin, BaseModel): @model_validator(mode="after") def validate_args(cls, values): - im_bytes = values.im_bytes - instance_uri = values.instance_uri + im_bytes = cls.im_bytes + instance_uri = cls.instance_uri if im_bytes == instance_uri == None: raise ValueError("One of `instance_uri`, `im_bytes` required.") - return values + return cls @field_validator("instance_uri") def validate_uri(cls, v): diff --git a/libs/labelbox/src/labelbox/data/mixins.py b/libs/labelbox/src/labelbox/data/mixins.py index de6a8c247..c6466279d 100644 --- a/libs/labelbox/src/labelbox/data/mixins.py +++ b/libs/labelbox/src/labelbox/data/mixins.py @@ -19,12 +19,6 @@ def confidence_valid_float(cls, value): raise ValueError("must be a number within [0,1] range") return value - @model_serializer(mode="wrap") - def serialize_model(self, handler): - res = handler(self) - res = _feature_serializer(res) - return res - class ConfidenceNotSupportedMixin: @@ -55,11 +49,6 @@ def value_valid_float(cls, value): class CustomMetricsMixin(BaseModel): custom_metrics: Optional[List[CustomMetric]] = None - @model_serializer(mode="wrap") - def serialize_model(self, handler): - res = handler(self) - return res - class CustomMetricsNotSupportedMixin: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index 2c26727f8..7cb8fed3b 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -23,10 +23,10 @@ class DataRow(_CamelCaseMixin): @model_validator(mode="after") - def must_set_one(cls, values): - if not is_exactly_one_set(values.id, values.global_key): + def must_set_one(cls): + if not is_exactly_one_set(cls.id, cls.global_key): raise ValueError("Must set either id or global_key") - return values + return cls class NDJsonBase(_CamelCaseMixin): @@ -42,16 +42,7 @@ class NDAnnotation(NDJsonBase): unit: Optional[str] = None @model_validator(mode="after") - def must_set_one(cls, values): - if (not hasattr(values, "schema_id") or values.schema_id is None) and (not hasattr(values, "name") or values.name is None): + def must_set_one(cls): + if (not hasattr(cls, "schema_id") or cls.schema_id is None) and (not hasattr(cls, "name") or cls.name is None): raise ValueError("Schema id or name are not set. Set either one.") - return values - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - res = handler(self) - if 'name' in res and res['name'] is None: - res.pop('name') - if 'schemaId' in res and res['schemaId'] is None: - res.pop('schemaId') - return res + return cls diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index d257d5ab0..4c04c9c09 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -21,12 +21,12 @@ class NDAnswer(ConfidenceMixin, CustomMetricsMixin): model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) @model_validator(mode="after") - def must_set_one(cls, values): - if (not hasattr(values, "schema_id") or values.schema_id is None) and (not hasattr(values, "name") or values.name is None): + def must_set_one(cls): + if (not hasattr(cls, "schema_id") or cls.schema_id is None) and (not hasattr(cls, "name") or cls.name is None): raise ValueError("Schema id or name are not set. Set either one.") - return values + return cls - @model_serializer(mode = "wrap") + @model_serializer(mode="wrap") def serialize_model(self, handler): res = handler(self) if 'name' in res and res['name'] is None: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index c79e45e6c..fd90b24eb 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -715,7 +715,7 @@ def from_common( if isinstance(first_video_annotation, DICOMObjectAnnotation): group_key = first_video_annotation.group_key.value args.update(dict(group_key=group_key)) - + return obj.from_common(**args) elif (obj == NDVideoMasks or obj == NDDicomMasks): return obj.from_common(annotation, data) diff --git a/libs/labelbox/src/labelbox/pydantic_serializers.py b/libs/labelbox/src/labelbox/pydantic_serializers.py deleted file mode 100644 index 8f2e94ff7..000000000 --- a/libs/labelbox/src/labelbox/pydantic_serializers.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Dict - - -def _check_keys(key: str) -> bool: - if "customMetrics" == key: - return True - if "custom_metrics" == key: - return True - if "keyframe" == key: - return True - if "classifications" == key: - return True - if "confidence" == key: - return True - if "name" == key: - return True - if 'featureSchemaId' == key: - return True - if "schemaId" == key: - return True - return False - -def _feature_serializer(res: Dict) -> Dict: - """Used with custom model serializer for Pydantics. This ensures backwards compatibility since Pydantic V1 allowed you to override dict/model_dump method that worked with nested models. This method needs to be used for all base classes and sub classes for same behavior with a model_serializer decorator. We should look at getting this removed by allowing our API to accept null values for fields that are optional.""" - for k, v in res.items(): - if _check_keys(k) and v == None: - del res[k] - if isinstance(res[k], Dict): - _feature_serializer(v) - return res - \ No newline at end of file diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index b95b72148..9166d6078 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -623,11 +623,11 @@ class NDFeatureSchema(BaseModel): name: Optional[str] = None @model_validator(mode="after") - def must_set_one(cls, values): - if values.schemaId is None and values.name is None: + def must_set_one(cls): + if cls.schemaId is None and cls.name is None: raise ValueError( "Must set either schemaId or name for all feature schemas") - return values + return cls class NDBase(NDFeatureSchema): diff --git a/libs/labelbox/src/labelbox/schema/consensus_settings.py b/libs/labelbox/src/labelbox/schema/consensus_settings.py index 001d51301..bd9cfc047 100644 --- a/libs/labelbox/src/labelbox/schema/consensus_settings.py +++ b/libs/labelbox/src/labelbox/schema/consensus_settings.py @@ -1,5 +1,4 @@ from labelbox.utils import _CamelCaseMixin -from pydantic import Field, AliasChoices class ConsensusSettings(_CamelCaseMixin): diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 7066f254a..3fc004c4a 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -10,8 +10,7 @@ from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey -from pydantic import BaseModel, Field, StringConstraints, ConfigDict, AliasGenerator, model_serializer, conlist, AliasChoices -from pydantic.alias_generators import to_camel +from pydantic import BaseModel, Field, StringConstraints, conlist from labelbox.schema.ontology import SchemaId from labelbox.utils import _CamelCaseMixin, format_iso_datetime, format_iso_from_string @@ -97,22 +96,6 @@ class _DeleteBatchDataRowMetadata(_CamelCaseMixin): data_row_identifier: Union[UniqueId, GlobalKey] schema_ids: List[SchemaId] - @model_serializer(mode="wrap") - def serialize_model(self, handler): - res = handler(self) - if 'data_row_identifier' in res.keys(): - key = 'data_row_identifier' - id_type_key = 'id_type' - else: - key = 'dataRowIdentifier' - id_type_key = 'idType' - data_row_identifier = res.pop(key) - res[key] = { - "id": data_row_identifier.key, - id_type_key: data_row_identifier.id_type - } - return res - _BatchInputs = Union[List[_UpsertBatchDataRowMetadata], List[_DeleteBatchDataRowMetadata]] @@ -959,7 +942,6 @@ def _validate_parse_text( raise ValueError( f"Expected a string type for the text field. Found {type(field.value)}" ) - print(String.metadata[0].max_length) if len(field.value) > String.metadata[0].max_length: raise ValueError( f"String fields cannot exceed {String.metadata.max_length} characters.") diff --git a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py index 516ae6d37..52d40ea57 100644 --- a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py +++ b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py @@ -42,16 +42,16 @@ class SendToAnnotateFromCatalogParams(BaseModel): batch_priority: Optional[int] = 5 @model_validator(mode="after") - def check_project_id_or_model_run_id(cls, values): - if not values.source_model_run_id and not values.source_project_id: + def check_project_id_or_model_run_id(cls): + if not cls.source_model_run_id and not cls.source_project_id: raise ValueError( 'Either source_project_id or source_model_id are required' ) - if values.source_model_run_id and values.source_project_id: + if cls.source_model_run_id and cls.source_project_id: raise ValueError( 'Provide only a source_project_id or source_model_id not both' ) - return values + return cls class SendToAnnotateFromModelParams(TypedDict): """ diff --git a/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json b/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json index 76235c40f..8f863ae7e 100644 --- a/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json +++ b/libs/labelbox/tests/data/assets/labelbox_v1/video_export.json @@ -5,8108 +5,7407 @@ "Media Attributes": {}, "Data Split": null, "Labeled Data": "https://storage.labelbox.com/cjhfn5y6s0pk507024nz1ocys%2Fb8837f3b-b071-98d9-645e-2e2c0302393b-jellyfish2-100-110.mp4?Expires=1627663739196&KeyName=labelbox-assets-key-3&Signature=JJ8HOcm57D7OclbC795cyjrrA3Q", - "Label": [ - { - "frameNumber": 1, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 582, - "left": 1644, - "height": 340, - "width": 212 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 712, - "left": 1256, - "height": 204, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 47, - "left": 155, - "height": 381, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 546, - "height": 263, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 361, - "height": 183, - "width": 207 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 2, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 595, - "left": 1635, - "height": 340, - "width": 212 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 719, - "left": 1246, - "height": 204, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 45, - "left": 148, - "height": 381, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 540, - "height": 262, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 353, - "height": 184, - "width": 209 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 3, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 600, - "left": 1628, - "height": 326, - "width": 212 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1233, - "height": 188, - "width": 332 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 46, - "left": 130, - "height": 381, - "width": 341 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 732, - "left": 536, - "height": 262, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 346, - "height": 183, - "width": 211 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 4, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 604, - "left": 1619, - "height": 322, - "width": 214 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1225, - "height": 180, - "width": 336 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 37, - "left": 123, - "height": 386, - "width": 343 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 732, - "left": 536, - "height": 269, - "width": 288 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 494, - "left": 338, - "height": 185, - "width": 216 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 5, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 619, - "left": 1606, - "height": 322, - "width": 214 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 729, - "left": 1208, - "height": 180, - "width": 336 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 36, - "left": 116, - "height": 386, - "width": 343 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 529, - "height": 269, - "width": 288 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 493, - "left": 332, - "height": 185, - "width": 216 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 6, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 1597, - "height": 322, - "width": 214 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 1195, - "height": 180, - "width": 336 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 30, - "left": 108, - "height": 386, - "width": 343 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 734.5, - "left": 522, - "height": 269, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 491, - "left": 326, - "height": 185, - "width": 216 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 7, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 632, - "left": 1586, - "height": 322, - "width": 214 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 1189, - "height": 175, - "width": 323 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 30, - "left": 86, - "height": 367, - "width": 354 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 515, - "height": 269, - "width": 292 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 490, - "left": 316, - "height": 183, - "width": 218 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 8, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 634, - "left": 1582, - "height": 321, - "width": 209 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 751, - "left": 1188, - "height": 170, - "width": 316 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 26, - "left": 78, - "height": 367, - "width": 354 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 500, - "height": 266, - "width": 302 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 488, - "left": 311, - "height": 183, - "width": 218 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 9, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 641, - "left": 1575, - "height": 321, - "width": 209 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 1188, - "height": 168, - "width": 307 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 23, - "left": 63, - "height": 372, - "width": 362 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 500, - "height": 270, - "width": 297 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 488, - "left": 305, - "height": 182, - "width": 219 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 10, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 648, - "left": 1563, - "height": 315, - "width": 203 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 1172, - "height": 172, - "width": 309 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 14, - "left": 48, - "height": 371, - "width": 366 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 493, - "height": 271, - "width": 304 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 486, - "left": 292, - "height": 184, - "width": 224 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 11, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 1555, - "height": 317, - "width": 208 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 1169, - "height": 174, - "width": 294 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 11, - "left": 47, - "height": 374, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 484, - "height": 271, - "width": 304 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 485, - "left": 287, - "height": 184, - "width": 224 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 12, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 1545, - "height": 317, - "width": 204 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 1162, - "height": 168, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 34, - "height": 374, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 476, - "height": 271, - "width": 304 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 479, - "left": 278, - "height": 184, - "width": 224 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 13, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 663, - "left": 1538, - "height": 317, - "width": 204 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 749, - "left": 1154, - "height": 173, - "width": 289 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 27, - "height": 374, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 473, - "height": 271, - "width": 304 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 476, - "left": 271, - "height": 183, - "width": 229 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 14, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 666, - "left": 1531, - "height": 314, - "width": 211 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 748, - "left": 1147, - "height": 176, - "width": 283 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 23, - "height": 312, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 470, - "height": 271, - "width": 304 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 470, - "left": 264, - "height": 187, - "width": 231 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 15, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 670, - "left": 1519, - "height": 316, - "width": 207 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 742, - "left": 1136, - "height": 187, - "width": 272 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 23, - "height": 281, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 457, - "height": 278, - "width": 312 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 464, - "left": 254, - "height": 193, - "width": 235 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 16, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 674, - "left": 1512, - "height": 311, - "width": 204 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 1129, - "height": 190, - "width": 279 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 19, - "height": 276, - "width": 356 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 457, - "height": 277, - "width": 306 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 457, - "left": 245, - "height": 189, - "width": 238 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 17, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 678, - "left": 1502, - "height": 310, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1118, - "height": 198, - "width": 267 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 271, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 725, - "left": 447, - "height": 277, - "width": 306 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 453, - "left": 236, - "height": 189, - "width": 238 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 18, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 679, - "left": 1496, - "height": 310, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1110, - "height": 203, - "width": 262 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 0, - "left": 0, - "height": 265.5, - "width": 360 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 725, - "left": 438, - "height": 276, - "width": 315 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 450, - "left": 227, - "height": 191, - "width": 244 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 19, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 685, - "left": 1489, - "height": 317, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 730, - "left": 1099, - "height": 206, - "width": 273 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 260, - "width": 353 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 438, - "height": 271, - "width": 307 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 449, - "left": 222, - "height": 183, - "width": 244 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 20, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 689, - "left": 1477, - "height": 317, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 731, - "left": 1086, - "height": 213, - "width": 260 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 258, - "width": 345 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 721, - "left": 431, - "height": 271, - "width": 308 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 448, - "left": 217, - "height": 177, - "width": 244 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 21, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 690, - "left": 1470, - "height": 317, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1077, - "height": 213, - "width": 260 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 259, - "width": 335 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 423, - "height": 271, - "width": 308 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 446, - "left": 212, - "height": 177, - "width": 244 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 22, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 697, - "left": 1458, - "height": 317, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1065, - "height": 213, - "width": 260 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 227, - "width": 313 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 736, - "left": 420, - "height": 250, - "width": 302 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 446, - "left": 212, - "height": 164, - "width": 236 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 23, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 701, - "left": 1449, - "height": 317, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 727, - "left": 1055, - "height": 219, - "width": 253 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 214, - "width": 307 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 417, - "height": 250, - "width": 302 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 432, - "left": 190, - "height": 147, - "width": 255 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 24, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 1447, - "height": 321, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 1049, - "height": 229, - "width": 250 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 202, - "width": 282 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 408, - "height": 235, - "width": 308 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 448, - "left": 209, - "height": 150, - "width": 228 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 25, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 708, - "left": 1433, - "height": 321, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1035, - "height": 229, - "width": 251 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 198, - "width": 272 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 759, - "left": 399, - "height": 234, - "width": 317 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 424, - "left": 170, - "height": 148, - "width": 262 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 26, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 714, - "left": 1425, - "height": 313, - "width": 194 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 1027, - "height": 240, - "width": 248 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 190, - "width": 272 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 392, - "height": 227, - "width": 322 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 413, - "left": 163, - "height": 152, - "width": 230 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 27, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 719, - "left": 1413, - "height": 313, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 1018, - "height": 235, - "width": 238 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 208, - "width": 284 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 754, - "left": 384.5, - "height": 228.5, - "width": 328.5 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 409, - "left": 151, - "height": 178, - "width": 268 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 28, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 724, - "left": 1408, - "height": 313, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 735, - "left": 1011, - "height": 217, - "width": 237 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 206, - "width": 281 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 377, - "height": 230, - "width": 335 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 409, - "left": 148, - "height": 178, - "width": 268 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 29, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 726, - "left": 1398, - "height": 313, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 1006, - "height": 205, - "width": 233 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 200, - "width": 274 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 750, - "left": 370, - "height": 232, - "width": 342 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 401, - "left": 138, - "height": 181, - "width": 275 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 30, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 1389, - "height": 313, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 751, - "left": 993, - "height": 182, - "width": 230 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 191, - "width": 261 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 745, - "left": 368, - "height": 232, - "width": 342 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 397, - "left": 132, - "height": 181, - "width": 275 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 31, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 733, - "left": 1381, - "height": 308, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 988, - "height": 181, - "width": 216 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 190, - "width": 258 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 368, - "height": 243, - "width": 341 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 394, - "left": 125, - "height": 181, - "width": 275 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 32, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 1369, - "height": 308, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 769, - "left": 979, - "height": 167, - "width": 204 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 181, - "width": 247 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 728, - "left": 367, - "height": 251, - "width": 341 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 387, - "left": 116, - "height": 182, - "width": 280 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 33, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 1361, - "height": 308, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 774, - "left": 973, - "height": 163, - "width": 199 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 176, - "width": 239 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 720, - "left": 368, - "height": 261, - "width": 340 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 383, - "left": 106, - "height": 180, - "width": 286 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 34, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 1353, - "height": 308, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 778, - "left": 967, - "height": 162, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 171, - "width": 235 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 718, - "left": 364, - "height": 257, - "width": 344 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 379, - "left": 100, - "height": 183, - "width": 287 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 35, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 749, - "left": 1343, - "height": 308, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 795, - "left": 957, - "height": 148, - "width": 178 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 160, - "width": 225 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 711, - "left": 363, - "height": 256, - "width": 343 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 375, - "left": 93.5, - "height": 187, - "width": 289.5 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 36, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 752, - "left": 1337, - "height": 309, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 796, - "left": 948, - "height": 149, - "width": 185 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 150, - "width": 216 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 710, - "left": 365, - "height": 269, - "width": 340 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 371, - "left": 87, - "height": 191, - "width": 292 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 37, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 758, - "left": 1324, - "height": 302, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 794, - "left": 935, - "height": 153, - "width": 177 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 131, - "width": 206 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 704, - "left": 360, - "height": 275, - "width": 342 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 365, - "left": 76, - "height": 194, - "width": 297 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 38, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 763, - "left": 1318, - "height": 302, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 789, - "left": 928, - "height": 160, - "width": 174 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 106, - "width": 199 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 702, - "left": 357, - "height": 277, - "width": 341 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 363, - "left": 70, - "height": 199, - "width": 300 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 39, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 1310, - "height": 302, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 786, - "left": 918, - "height": 164, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 38, - "width": 134 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 695, - "left": 357, - "height": 282, - "width": 340 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 359, - "left": 64, - "height": 200, - "width": 302 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 40, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 770, - "left": 1299, - "height": 302, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 775, - "left": 905, - "height": 177, - "width": 177 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eo0y6188xz7m35", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 16, - "width": 111 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 694, - "left": 354, - "height": 282, - "width": 338 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 353, - "left": 56, - "height": 203, - "width": 305 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 41, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 772, - "left": 1289, - "height": 302, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 896, - "height": 185, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 688.5, - "left": 351.5, - "height": 287, - "width": 338.5 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 350, - "left": 51, - "height": 203, - "width": 306 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 321, - "left": 569, - "height": 125, - "width": 109 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 42, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 775, - "left": 1281, - "height": 297, - "width": 188 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 754, - "left": 884, - "height": 196, - "width": 175 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 683, - "left": 349, - "height": 292, - "width": 339 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 342, - "left": 41, - "height": 204, - "width": 310 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 317, - "left": 559.5, - "height": 126, - "width": 111 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 43, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 778, - "left": 1273, - "height": 297, - "width": 188 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 748, - "left": 875, - "height": 202, - "width": 152 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 682, - "left": 346, - "height": 292, - "width": 339 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 335, - "left": 37, - "height": 204, - "width": 310 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 313, - "left": 550, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 44, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 779, - "left": 1266, - "height": 293, - "width": 188 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 741, - "left": 865, - "height": 211, - "width": 158 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 681, - "left": 345, - "height": 292, - "width": 339 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 331, - "left": 33, - "height": 204, - "width": 310 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 309, - "left": 543, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 45, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 785, - "left": 1255, - "height": 293, - "width": 188 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 734, - "left": 855.5, - "height": 217.5, - "width": 160 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 672, - "left": 340, - "height": 296, - "width": 339 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 322, - "left": 28, - "height": 211, - "width": 311 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 303, - "left": 532, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 46, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 784, - "left": 1245, - "height": 293, - "width": 188 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 727, - "left": 846, - "height": 224, - "width": 162 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 669, - "left": 344, - "height": 297, - "width": 333 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 314, - "left": 23, - "height": 211, - "width": 311 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 298, - "left": 526, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 47, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 787, - "left": 1234, - "height": 290, - "width": 186 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 723, - "left": 832, - "height": 224, - "width": 165 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 668, - "left": 339, - "height": 297, - "width": 333 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 306, - "left": 12, - "height": 211, - "width": 315 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 291, - "left": 514, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 48, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 790, - "left": 1227, - "height": 286, - "width": 187 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 714, - "left": 824, - "height": 235, - "width": 167 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 667, - "left": 335, - "height": 297, - "width": 333 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 301, - "left": 7, - "height": 211, - "width": 315 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 289, - "left": 506, - "height": 127, - "width": 113 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 49, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 792, - "left": 1216, - "height": 286, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 710, - "left": 815, - "height": 238, - "width": 167 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 664, - "left": 337, - "height": 297, - "width": 327 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 298, - "left": 0, - "height": 214, - "width": 319 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 285, - "left": 498, - "height": 127, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 50, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 797, - "left": 1205, - "height": 283, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 815, - "height": 239, - "width": 157 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 658, - "left": 334, - "height": 302, - "width": 327 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 290, - "left": 0, - "height": 217, - "width": 312 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 281, - "left": 485, - "height": 127, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 51, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 797, - "left": 1197, - "height": 283, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 812, - "height": 240, - "width": 157 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 328, - "height": 302, - "width": 327 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 284, - "left": 0, - "height": 223, - "width": 310 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 277, - "left": 478, - "height": 127, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 52, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 801, - "left": 1183, - "height": 279, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 802, - "height": 243, - "width": 150 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 657, - "left": 322, - "height": 299, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 279, - "left": 0, - "height": 220, - "width": 302 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 271, - "left": 465, - "height": 129, - "width": 117 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 53, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 807, - "left": 1177, - "height": 273, - "width": 191 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 802, - "height": 243, - "width": 144 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 659, - "left": 316, - "height": 297, - "width": 333 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 274, - "left": 0, - "height": 225, - "width": 298 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 270, - "left": 456, - "height": 129, - "width": 117 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 54, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 807, - "left": 1167, - "height": 273, - "width": 191 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 704, - "left": 792, - "height": 247, - "width": 145 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 312, - "height": 306, - "width": 332 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 270, - "left": 0, - "height": 229, - "width": 295 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 266, - "left": 448, - "height": 129, - "width": 117 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 55, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 1156, - "height": 267, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 706, - "left": 783, - "height": 247, - "width": 145 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 310, - "height": 304, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 260, - "left": 0, - "height": 231, - "width": 290 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 261, - "left": 435, - "height": 129, - "width": 118 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 56, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 1148, - "height": 267, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 706, - "left": 784, - "height": 248, - "width": 147 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 650, - "left": 308, - "height": 304, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 257, - "left": 0, - "height": 234, - "width": 286 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 260, - "left": 428, - "height": 129, - "width": 118 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 57, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 819, - "left": 1134, - "height": 261, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 705, - "left": 776, - "height": 248, - "width": 146 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 647, - "left": 303, - "height": 304, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 250, - "left": 0, - "height": 235, - "width": 283 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 255, - "left": 415, - "height": 128, - "width": 120 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 58, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 822, - "left": 1127, - "height": 258, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 707, - "left": 775, - "height": 250, - "width": 138 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 648, - "left": 300, - "height": 304, - "width": 330 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 246, - "left": 0, - "height": 236, - "width": 279 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 250, - "left": 406, - "height": 128, - "width": 120 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 59, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 825, - "left": 1120, - "height": 255, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 709.5, - "left": 780, - "height": 249, - "width": 124 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 645, - "left": 297.5, - "height": 306.5, - "width": 328 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 244, - "left": 11, - "height": 238, - "width": 265 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 248, - "left": 396, - "height": 127.5, - "width": 122 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 60, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 828, - "left": 1108, - "height": 252, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 712, - "left": 785, - "height": 248, - "width": 110 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 642, - "left": 295, - "height": 309, - "width": 326 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 238, - "left": 24, - "height": 244, - "width": 248 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 246, - "left": 386, - "height": 127, - "width": 124 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 61, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 832, - "left": 1099, - "height": 248, - "width": 191 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 716, - "left": 790, - "height": 241, - "width": 98 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 640, - "left": 279.5, - "height": 310, - "width": 340 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 233, - "left": 41, - "height": 243, - "width": 227 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 243, - "left": 379, - "height": 128, - "width": 123 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 62, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 836, - "left": 1088, - "height": 244, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 894, - "left": 777, - "height": 63, - "width": 99 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 638, - "left": 264, - "height": 311, - "width": 354 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 227, - "left": 43, - "height": 234, - "width": 221 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 238, - "left": 367, - "height": 128, - "width": 123 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 63, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 840, - "left": 1081, - "height": 240, - "width": 191 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 776, - "height": 60, - "width": 94 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 638, - "left": 256, - "height": 312, - "width": 359 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 226, - "left": 38, - "height": 225, - "width": 226 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 235, - "left": 361, - "height": 128, - "width": 123 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 64, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 843, - "left": 1074, - "height": 237, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 860, - "left": 723, - "height": 85.5, - "width": 131 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 636.5, - "left": 250, - "height": 313, - "width": 363 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 222, - "left": 31, - "height": 222, - "width": 229 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 230, - "left": 361, - "height": 131, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 65, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 847, - "left": 1064, - "height": 233, - "width": 190 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 828, - "left": 670, - "height": 111, - "width": 168 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 635, - "left": 244, - "height": 314, - "width": 367 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 216, - "left": 29, - "height": 190, - "width": 228 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 227, - "left": 350, - "height": 131, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 66, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1054, - "height": 228, - "width": 192 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 813, - "left": 662, - "height": 116, - "width": 169 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 634.5, - "left": 239, - "height": 313, - "width": 369 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 214, - "left": 29, - "height": 163, - "width": 227 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 222, - "left": 343, - "height": 131, - "width": 115 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 67, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1042, - "height": 228, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 808, - "left": 651, - "height": 122, - "width": 166 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 634, - "left": 234, - "height": 312, - "width": 371 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 209, - "left": 23, - "height": 161, - "width": 229 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 220, - "left": 337, - "height": 130, - "width": 110 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 68, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 852, - "left": 1035, - "height": 228, - "width": 193 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 808, - "left": 651, - "height": 122, - "width": 156 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 224, - "height": 322, - "width": 377 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 203, - "left": 24, - "height": 163, - "width": 227 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 217, - "left": 329, - "height": 130, - "width": 108 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 69, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 857, - "left": 1028, - "height": 223, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 802, - "left": 637, - "height": 127, - "width": 158 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 623, - "left": 220.667, - "height": 321.667, - "width": 379.333 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 203, - "left": 19, - "height": 153, - "width": 231 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 213, - "left": 325, - "height": 130, - "width": 108 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 70, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 864, - "left": 1016, - "height": 216, - "width": 198 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 802, - "left": 629.5, - "height": 129.5, - "width": 153 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 623, - "left": 217.333, - "height": 321.333, - "width": 381.667 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 202.5, - "left": 19.5, - "height": 142.5, - "width": 228 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 212, - "left": 315, - "height": 124.5, - "width": 108 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 71, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 864, - "left": 1009, - "height": 216, - "width": 198 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 802, - "left": 622, - "height": 132, - "width": 148 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 623, - "left": 214, - "height": 321, - "width": 384 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 202, - "left": 20, - "height": 132, - "width": 225 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 211, - "left": 305, - "height": 119, - "width": 108 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 72, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 868, - "left": 994, - "height": 212, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 798, - "left": 610, - "height": 138, - "width": 165 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 620, - "left": 203, - "height": 323, - "width": 388 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 189, - "left": 16, - "height": 137, - "width": 227 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 212, - "left": 294, - "height": 114, - "width": 108 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 73, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 873, - "left": 987, - "height": 207, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 787, - "left": 603, - "height": 151, - "width": 172 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 620, - "left": 203, - "height": 323, - "width": 389 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 183, - "left": 17, - "height": 126, - "width": 223 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 211, - "left": 286, - "height": 112, - "width": 109 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 74, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 873, - "left": 980, - "height": 207, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 596, - "height": 150, - "width": 173 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 615, - "left": 195, - "height": 323, - "width": 389 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 173, - "left": 10, - "height": 123, - "width": 229 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 209, - "left": 278, - "height": 112, - "width": 107 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 75, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 878, - "left": 968, - "height": 202, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 588, - "height": 143, - "width": 175 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 616, - "left": 188, - "height": 323, - "width": 389 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 168, - "left": 5, - "height": 113, - "width": 234 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 213, - "left": 276, - "height": 98, - "width": 98 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 76, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 882, - "left": 961, - "height": 198, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 788, - "left": 582, - "height": 143, - "width": 175 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 614, - "left": 185, - "height": 326, - "width": 396 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 168, - "left": 0, - "height": 103, - "width": 237 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 217, - "left": 276, - "height": 86, - "width": 93 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 77, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 882, - "left": 950, - "height": 198, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 768, - "left": 573, - "height": 174, - "width": 175 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 613, - "left": 182, - "height": 327, - "width": 399 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 161, - "left": 0, - "height": 112, - "width": 232 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 223, - "left": 282, - "height": 55, - "width": 76 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 78, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 886, - "left": 944, - "height": 194, - "width": 199 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 763, - "left": 567, - "height": 179, - "width": 177 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 613, - "left": 182, - "height": 324, - "width": 399 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 158, - "left": 0, - "height": 118, - "width": 224 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 225, - "left": 301, - "height": 47, - "width": 49 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 79, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 886, - "left": 936, - "height": 194, - "width": 199 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 760, - "left": 562, - "height": 181, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 611, - "left": 179, - "height": 324, - "width": 399 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 154, - "left": 0, - "height": 179, - "width": 218 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06er0y612emohrkf", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 225, - "left": 309, - "height": 41, - "width": 33 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 80, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 925, - "height": 189, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 762, - "left": 555, - "height": 181, - "width": 174 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 608, - "left": 177, - "height": 327, - "width": 401 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 144, - "left": 0, - "height": 239, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1352, - "height": 202, - "width": 217 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 81, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 920, - "height": 189, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 765, - "left": 552, - "height": 172, - "width": 164 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 602, - "left": 179, - "height": 328, - "width": 393 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 140, - "left": 0, - "height": 235, - "width": 208 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 341, - "left": 1347, - "height": 202, - "width": 217 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 82, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 891, - "left": 910, - "height": 189, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 765, - "left": 544, - "height": 173, - "width": 174 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 602, - "left": 179, - "height": 327, - "width": 393 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 132, - "left": 0, - "height": 235, - "width": 208 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 342, - "left": 1336, - "height": 202, - "width": 217 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 83, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 898, - "height": 184, - "width": 200 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 769, - "left": 541, - "height": 162, - "width": 169 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 598, - "left": 175, - "height": 327, - "width": 393 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 123, - "left": 0, - "height": 238, - "width": 208 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1331, - "height": 203, - "width": 217 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 84, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 889, - "height": 184, - "width": 203 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 767, - "left": 537, - "height": 153, - "width": 168 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 595, - "left": 171, - "height": 327, - "width": 393 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 117, - "left": 0, - "height": 238, - "width": 208 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1326, - "height": 203, - "width": 217 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 85, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 879, - "height": 184, - "width": 203 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 766, - "left": 531, - "height": 160, - "width": 162 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 585, - "left": 165, - "height": 332, - "width": 400 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 103, - "left": 0, - "height": 272, - "width": 210 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1318, - "height": 204, - "width": 215 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 86, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 895, - "left": 868, - "height": 185, - "width": 205 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 759, - "left": 526, - "height": 159, - "width": 161 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 584, - "left": 164, - "height": 329, - "width": 400 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 94, - "left": 0, - "height": 274, - "width": 211 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 343, - "left": 1312, - "height": 204, - "width": 215 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 87, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 855, - "height": 188, - "width": 206 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 755, - "left": 517, - "height": 159, - "width": 161 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 574, - "left": 210, - "height": 334, - "width": 349 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 78, - "left": 0, - "height": 281, - "width": 215 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 341, - "left": 1300, - "height": 204, - "width": 215 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 88, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 849, - "height": 190, - "width": 206 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 753, - "left": 512, - "height": 163, - "width": 161 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 569, - "left": 207, - "height": 333, - "width": 352 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 71, - "left": 0, - "height": 281, - "width": 220 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1294, - "height": 204, - "width": 215 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 89, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 839, - "height": 190, - "width": 209 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 746, - "left": 505, - "height": 166, - "width": 170 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 562, - "left": 203, - "height": 333, - "width": 352 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 62, - "left": 0, - "height": 281, - "width": 221 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1288, - "height": 204, - "width": 215 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 90, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 832, - "height": 188, - "width": 203 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 747, - "left": 498, - "height": 143, - "width": 175 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 557, - "left": 196, - "height": 333, - "width": 352 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 47, - "left": 0, - "height": 283, - "width": 217 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1279, - "height": 205, - "width": 203 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 91, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 892, - "left": 830, - "height": 188, - "width": 197 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 747, - "left": 495, - "height": 141, - "width": 174 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 549, - "left": 193, - "height": 340, - "width": 353 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 38, - "left": 0, - "height": 283, - "width": 217 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 335, - "left": 1272, - "height": 208, - "width": 207 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 92, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 890, - "left": 826, - "height": 190, - "width": 189 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 487, - "height": 146, - "width": 145 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 546, - "left": 187, - "height": 334, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 27, - "left": 0, - "height": 285, - "width": 213 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 334, - "left": 1263, - "height": 208, - "width": 207 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 93, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 813, - "height": 187, - "width": 196 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 743, - "left": 478, - "height": 143, - "width": 179 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 540, - "left": 187, - "height": 343, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 17, - "left": 0, - "height": 292, - "width": 213 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1258, - "height": 208, - "width": 198 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 94, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 893.5, - "left": 812, - "height": 186.5, - "width": 186 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 735, - "left": 474, - "height": 149, - "width": 177 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 533, - "left": 184, - "height": 343, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 9, - "left": 0, - "height": 292, - "width": 213 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1251, - "height": 208, - "width": 198 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 95, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 894, - "left": 811, - "height": 186, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 737, - "left": 465, - "height": 146, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 534, - "left": 181, - "height": 340, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 293, - "width": 209 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 336, - "left": 1240, - "height": 208, - "width": 192 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 96, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 898, - "left": 809, - "height": 182, - "width": 171 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 460, - "height": 143, - "width": 181 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 528, - "left": 178, - "height": 340, - "width": 357 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 288, - "width": 210 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 336, - "left": 1234, - "height": 211, - "width": 195 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 97, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 896, - "left": 805, - "height": 184, - "width": 165 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 740, - "left": 455, - "height": 138, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 524.5, - "left": 178, - "height": 343.5, - "width": 357.5 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 278, - "width": 213 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1223, - "height": 211, - "width": 195 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 98, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 800, - "height": 187, - "width": 163 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 741, - "left": 449, - "height": 134, - "width": 176 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 521, - "left": 178, - "height": 347, - "width": 358 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 268, - "width": 211 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 337, - "left": 1219, - "height": 211, - "width": 195 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 99, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 893, - "left": 795, - "height": 187, - "width": 160 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 739, - "left": 449, - "height": 136, - "width": 171 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 515, - "left": 178, - "height": 345, - "width": 359 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 266, - "width": 215 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 339, - "left": 1214, - "height": 211, - "width": 195 - }, - "classifications": [] - } - ] - }, - { - "frameNumber": 100, - "classifications": [], - "objects": [ - { - "featureId": "ckqcx1d9x06em0y618b90atyy", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 898, - "left": 786, - "height": 182, - "width": 158 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06en0y612vo2feu6", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 738, - "left": 467, - "height": 136, - "width": 146 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06ep0y617a2f5wbs", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": false, - "bbox": { - "top": 515, - "left": 178, - "height": 345, - "width": 359 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06eq0y6136uoa1xg", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 0, - "left": 0, - "height": 256, - "width": 217 - }, - "classifications": [] - }, - { - "featureId": "ckqcx1d9x06es0y61gvx60aqk", - "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", - "title": "Jellyfish", - "value": "jellyfish", - "color": "#a23030", - "keyframe": true, - "bbox": { - "top": 338, - "left": 1203, - "height": 211, - "width": 195 - }, - "classifications": [] - } - ] - } - ], + "Label": [{ + "frameNumber": 1, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 582, + "left": 1644, + "height": 340, + "width": 212 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 712, + "left": 1256, + "height": 204, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 47, + "left": 155, + "height": 381, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 546, + "height": 263, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 361, + "height": 183, + "width": 207 + }, + "classifications": [] + }] + }, { + "frameNumber": 2, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 595, + "left": 1635, + "height": 340, + "width": 212 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 719, + "left": 1246, + "height": 204, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 45, + "left": 148, + "height": 381, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 540, + "height": 262, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 353, + "height": 184, + "width": 209 + }, + "classifications": [] + }] + }, { + "frameNumber": 3, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 600, + "left": 1628, + "height": 326, + "width": 212 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1233, + "height": 188, + "width": 332 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 46, + "left": 130, + "height": 381, + "width": 341 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 732, + "left": 536, + "height": 262, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 346, + "height": 183, + "width": 211 + }, + "classifications": [] + }] + }, { + "frameNumber": 4, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 604, + "left": 1619, + "height": 322, + "width": 214 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1225, + "height": 180, + "width": 336 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 37, + "left": 123, + "height": 386, + "width": 343 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 732, + "left": 536, + "height": 269, + "width": 288 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 494, + "left": 338, + "height": 185, + "width": 216 + }, + "classifications": [] + }] + }, { + "frameNumber": 5, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 619, + "left": 1606, + "height": 322, + "width": 214 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 729, + "left": 1208, + "height": 180, + "width": 336 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 36, + "left": 116, + "height": 386, + "width": 343 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 529, + "height": 269, + "width": 288 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 493, + "left": 332, + "height": 185, + "width": 216 + }, + "classifications": [] + }] + }, { + "frameNumber": 6, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 1597, + "height": 322, + "width": 214 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 1195, + "height": 180, + "width": 336 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 30, + "left": 108, + "height": 386, + "width": 343 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 734.5, + "left": 522, + "height": 269, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 491, + "left": 326, + "height": 185, + "width": 216 + }, + "classifications": [] + }] + }, { + "frameNumber": 7, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 632, + "left": 1586, + "height": 322, + "width": 214 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 1189, + "height": 175, + "width": 323 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 30, + "left": 86, + "height": 367, + "width": 354 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 515, + "height": 269, + "width": 292 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 490, + "left": 316, + "height": 183, + "width": 218 + }, + "classifications": [] + }] + }, { + "frameNumber": 8, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 634, + "left": 1582, + "height": 321, + "width": 209 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 751, + "left": 1188, + "height": 170, + "width": 316 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 26, + "left": 78, + "height": 367, + "width": 354 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 500, + "height": 266, + "width": 302 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 488, + "left": 311, + "height": 183, + "width": 218 + }, + "classifications": [] + }] + }, { + "frameNumber": 9, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 641, + "left": 1575, + "height": 321, + "width": 209 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 1188, + "height": 168, + "width": 307 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 23, + "left": 63, + "height": 372, + "width": 362 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 500, + "height": 270, + "width": 297 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 488, + "left": 305, + "height": 182, + "width": 219 + }, + "classifications": [] + }] + }, { + "frameNumber": 10, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 648, + "left": 1563, + "height": 315, + "width": 203 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 1172, + "height": 172, + "width": 309 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 14, + "left": 48, + "height": 371, + "width": 366 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 493, + "height": 271, + "width": 304 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 486, + "left": 292, + "height": 184, + "width": 224 + }, + "classifications": [] + }] + }, { + "frameNumber": 11, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 1555, + "height": 317, + "width": 208 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 1169, + "height": 174, + "width": 294 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 11, + "left": 47, + "height": 374, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 484, + "height": 271, + "width": 304 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 485, + "left": 287, + "height": 184, + "width": 224 + }, + "classifications": [] + }] + }, { + "frameNumber": 12, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 1545, + "height": 317, + "width": 204 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 1162, + "height": 168, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 34, + "height": 374, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 476, + "height": 271, + "width": 304 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 479, + "left": 278, + "height": 184, + "width": 224 + }, + "classifications": [] + }] + }, { + "frameNumber": 13, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 663, + "left": 1538, + "height": 317, + "width": 204 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 749, + "left": 1154, + "height": 173, + "width": 289 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 27, + "height": 374, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 473, + "height": 271, + "width": 304 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 476, + "left": 271, + "height": 183, + "width": 229 + }, + "classifications": [] + }] + }, { + "frameNumber": 14, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 666, + "left": 1531, + "height": 314, + "width": 211 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 748, + "left": 1147, + "height": 176, + "width": 283 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 23, + "height": 312, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 470, + "height": 271, + "width": 304 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 470, + "left": 264, + "height": 187, + "width": 231 + }, + "classifications": [] + }] + }, { + "frameNumber": 15, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 670, + "left": 1519, + "height": 316, + "width": 207 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 742, + "left": 1136, + "height": 187, + "width": 272 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 23, + "height": 281, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 457, + "height": 278, + "width": 312 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 464, + "left": 254, + "height": 193, + "width": 235 + }, + "classifications": [] + }] + }, { + "frameNumber": 16, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 674, + "left": 1512, + "height": 311, + "width": 204 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 1129, + "height": 190, + "width": 279 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 19, + "height": 276, + "width": 356 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 457, + "height": 277, + "width": 306 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 457, + "left": 245, + "height": 189, + "width": 238 + }, + "classifications": [] + }] + }, { + "frameNumber": 17, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 678, + "left": 1502, + "height": 310, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1118, + "height": 198, + "width": 267 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 271, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 725, + "left": 447, + "height": 277, + "width": 306 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 453, + "left": 236, + "height": 189, + "width": 238 + }, + "classifications": [] + }] + }, { + "frameNumber": 18, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 679, + "left": 1496, + "height": 310, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1110, + "height": 203, + "width": 262 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 0, + "left": 0, + "height": 265.5, + "width": 360 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 725, + "left": 438, + "height": 276, + "width": 315 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 450, + "left": 227, + "height": 191, + "width": 244 + }, + "classifications": [] + }] + }, { + "frameNumber": 19, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 685, + "left": 1489, + "height": 317, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 730, + "left": 1099, + "height": 206, + "width": 273 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 260, + "width": 353 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 438, + "height": 271, + "width": 307 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 449, + "left": 222, + "height": 183, + "width": 244 + }, + "classifications": [] + }] + }, { + "frameNumber": 20, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 689, + "left": 1477, + "height": 317, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 731, + "left": 1086, + "height": 213, + "width": 260 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 258, + "width": 345 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 721, + "left": 431, + "height": 271, + "width": 308 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 448, + "left": 217, + "height": 177, + "width": 244 + }, + "classifications": [] + }] + }, { + "frameNumber": 21, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 690, + "left": 1470, + "height": 317, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1077, + "height": 213, + "width": 260 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 259, + "width": 335 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 423, + "height": 271, + "width": 308 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 446, + "left": 212, + "height": 177, + "width": 244 + }, + "classifications": [] + }] + }, { + "frameNumber": 22, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 697, + "left": 1458, + "height": 317, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1065, + "height": 213, + "width": 260 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 227, + "width": 313 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 736, + "left": 420, + "height": 250, + "width": 302 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 446, + "left": 212, + "height": 164, + "width": 236 + }, + "classifications": [] + }] + }, { + "frameNumber": 23, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 701, + "left": 1449, + "height": 317, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 727, + "left": 1055, + "height": 219, + "width": 253 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 214, + "width": 307 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 417, + "height": 250, + "width": 302 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 432, + "left": 190, + "height": 147, + "width": 255 + }, + "classifications": [] + }] + }, { + "frameNumber": 24, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 1447, + "height": 321, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 1049, + "height": 229, + "width": 250 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 202, + "width": 282 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 408, + "height": 235, + "width": 308 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 448, + "left": 209, + "height": 150, + "width": 228 + }, + "classifications": [] + }] + }, { + "frameNumber": 25, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 708, + "left": 1433, + "height": 321, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1035, + "height": 229, + "width": 251 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 198, + "width": 272 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 759, + "left": 399, + "height": 234, + "width": 317 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 424, + "left": 170, + "height": 148, + "width": 262 + }, + "classifications": [] + }] + }, { + "frameNumber": 26, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 714, + "left": 1425, + "height": 313, + "width": 194 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 1027, + "height": 240, + "width": 248 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 190, + "width": 272 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 392, + "height": 227, + "width": 322 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 413, + "left": 163, + "height": 152, + "width": 230 + }, + "classifications": [] + }] + }, { + "frameNumber": 27, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 719, + "left": 1413, + "height": 313, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 1018, + "height": 235, + "width": 238 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 208, + "width": 284 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 754, + "left": 384.5, + "height": 228.5, + "width": 328.5 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 409, + "left": 151, + "height": 178, + "width": 268 + }, + "classifications": [] + }] + }, { + "frameNumber": 28, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 724, + "left": 1408, + "height": 313, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 735, + "left": 1011, + "height": 217, + "width": 237 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 206, + "width": 281 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 377, + "height": 230, + "width": 335 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 409, + "left": 148, + "height": 178, + "width": 268 + }, + "classifications": [] + }] + }, { + "frameNumber": 29, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 726, + "left": 1398, + "height": 313, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 1006, + "height": 205, + "width": 233 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 200, + "width": 274 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 750, + "left": 370, + "height": 232, + "width": 342 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 401, + "left": 138, + "height": 181, + "width": 275 + }, + "classifications": [] + }] + }, { + "frameNumber": 30, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 1389, + "height": 313, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 751, + "left": 993, + "height": 182, + "width": 230 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 191, + "width": 261 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 745, + "left": 368, + "height": 232, + "width": 342 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 397, + "left": 132, + "height": 181, + "width": 275 + }, + "classifications": [] + }] + }, { + "frameNumber": 31, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 733, + "left": 1381, + "height": 308, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 988, + "height": 181, + "width": 216 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 190, + "width": 258 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 368, + "height": 243, + "width": 341 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 394, + "left": 125, + "height": 181, + "width": 275 + }, + "classifications": [] + }] + }, { + "frameNumber": 32, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 1369, + "height": 308, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 769, + "left": 979, + "height": 167, + "width": 204 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 181, + "width": 247 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 728, + "left": 367, + "height": 251, + "width": 341 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 387, + "left": 116, + "height": 182, + "width": 280 + }, + "classifications": [] + }] + }, { + "frameNumber": 33, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 1361, + "height": 308, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 774, + "left": 973, + "height": 163, + "width": 199 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 176, + "width": 239 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 720, + "left": 368, + "height": 261, + "width": 340 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 383, + "left": 106, + "height": 180, + "width": 286 + }, + "classifications": [] + }] + }, { + "frameNumber": 34, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 1353, + "height": 308, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 778, + "left": 967, + "height": 162, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 171, + "width": 235 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 718, + "left": 364, + "height": 257, + "width": 344 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 379, + "left": 100, + "height": 183, + "width": 287 + }, + "classifications": [] + }] + }, { + "frameNumber": 35, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 749, + "left": 1343, + "height": 308, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 795, + "left": 957, + "height": 148, + "width": 178 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 160, + "width": 225 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 711, + "left": 363, + "height": 256, + "width": 343 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 375, + "left": 93.5, + "height": 187, + "width": 289.5 + }, + "classifications": [] + }] + }, { + "frameNumber": 36, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 752, + "left": 1337, + "height": 309, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 796, + "left": 948, + "height": 149, + "width": 185 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 150, + "width": 216 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 710, + "left": 365, + "height": 269, + "width": 340 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 371, + "left": 87, + "height": 191, + "width": 292 + }, + "classifications": [] + }] + }, { + "frameNumber": 37, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 758, + "left": 1324, + "height": 302, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 794, + "left": 935, + "height": 153, + "width": 177 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 131, + "width": 206 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 704, + "left": 360, + "height": 275, + "width": 342 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 365, + "left": 76, + "height": 194, + "width": 297 + }, + "classifications": [] + }] + }, { + "frameNumber": 38, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 763, + "left": 1318, + "height": 302, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 789, + "left": 928, + "height": 160, + "width": 174 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 106, + "width": 199 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 702, + "left": 357, + "height": 277, + "width": 341 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 363, + "left": 70, + "height": 199, + "width": 300 + }, + "classifications": [] + }] + }, { + "frameNumber": 39, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 1310, + "height": 302, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 786, + "left": 918, + "height": 164, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 38, + "width": 134 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 695, + "left": 357, + "height": 282, + "width": 340 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 359, + "left": 64, + "height": 200, + "width": 302 + }, + "classifications": [] + }] + }, { + "frameNumber": 40, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 770, + "left": 1299, + "height": 302, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 775, + "left": 905, + "height": 177, + "width": 177 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eo0y6188xz7m35", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 16, + "width": 111 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 694, + "left": 354, + "height": 282, + "width": 338 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 353, + "left": 56, + "height": 203, + "width": 305 + }, + "classifications": [] + }] + }, { + "frameNumber": 41, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 772, + "left": 1289, + "height": 302, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 896, + "height": 185, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 688.5, + "left": 351.5, + "height": 287, + "width": 338.5 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 350, + "left": 51, + "height": 203, + "width": 306 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 321, + "left": 569, + "height": 125, + "width": 109 + }, + "classifications": [] + }] + }, { + "frameNumber": 42, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 775, + "left": 1281, + "height": 297, + "width": 188 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 754, + "left": 884, + "height": 196, + "width": 175 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 683, + "left": 349, + "height": 292, + "width": 339 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 342, + "left": 41, + "height": 204, + "width": 310 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 317, + "left": 559.5, + "height": 126, + "width": 111 + }, + "classifications": [] + }] + }, { + "frameNumber": 43, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 778, + "left": 1273, + "height": 297, + "width": 188 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 748, + "left": 875, + "height": 202, + "width": 152 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 682, + "left": 346, + "height": 292, + "width": 339 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 335, + "left": 37, + "height": 204, + "width": 310 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 313, + "left": 550, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 44, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 779, + "left": 1266, + "height": 293, + "width": 188 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 741, + "left": 865, + "height": 211, + "width": 158 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 681, + "left": 345, + "height": 292, + "width": 339 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 331, + "left": 33, + "height": 204, + "width": 310 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 309, + "left": 543, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 45, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 785, + "left": 1255, + "height": 293, + "width": 188 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 734, + "left": 855.5, + "height": 217.5, + "width": 160 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 672, + "left": 340, + "height": 296, + "width": 339 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 322, + "left": 28, + "height": 211, + "width": 311 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 303, + "left": 532, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 46, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 784, + "left": 1245, + "height": 293, + "width": 188 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 727, + "left": 846, + "height": 224, + "width": 162 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 669, + "left": 344, + "height": 297, + "width": 333 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 314, + "left": 23, + "height": 211, + "width": 311 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 298, + "left": 526, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 47, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 787, + "left": 1234, + "height": 290, + "width": 186 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 723, + "left": 832, + "height": 224, + "width": 165 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 668, + "left": 339, + "height": 297, + "width": 333 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 306, + "left": 12, + "height": 211, + "width": 315 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 291, + "left": 514, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 48, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 790, + "left": 1227, + "height": 286, + "width": 187 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 714, + "left": 824, + "height": 235, + "width": 167 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 667, + "left": 335, + "height": 297, + "width": 333 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 301, + "left": 7, + "height": 211, + "width": 315 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 289, + "left": 506, + "height": 127, + "width": 113 + }, + "classifications": [] + }] + }, { + "frameNumber": 49, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 792, + "left": 1216, + "height": 286, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 710, + "left": 815, + "height": 238, + "width": 167 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 664, + "left": 337, + "height": 297, + "width": 327 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 298, + "left": 0, + "height": 214, + "width": 319 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 285, + "left": 498, + "height": 127, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 50, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 797, + "left": 1205, + "height": 283, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 815, + "height": 239, + "width": 157 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 658, + "left": 334, + "height": 302, + "width": 327 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 290, + "left": 0, + "height": 217, + "width": 312 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 281, + "left": 485, + "height": 127, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 51, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 797, + "left": 1197, + "height": 283, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 812, + "height": 240, + "width": 157 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 328, + "height": 302, + "width": 327 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 284, + "left": 0, + "height": 223, + "width": 310 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 277, + "left": 478, + "height": 127, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 52, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 801, + "left": 1183, + "height": 279, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 802, + "height": 243, + "width": 150 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 657, + "left": 322, + "height": 299, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 279, + "left": 0, + "height": 220, + "width": 302 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 271, + "left": 465, + "height": 129, + "width": 117 + }, + "classifications": [] + }] + }, { + "frameNumber": 53, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 807, + "left": 1177, + "height": 273, + "width": 191 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 802, + "height": 243, + "width": 144 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 659, + "left": 316, + "height": 297, + "width": 333 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 274, + "left": 0, + "height": 225, + "width": 298 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 270, + "left": 456, + "height": 129, + "width": 117 + }, + "classifications": [] + }] + }, { + "frameNumber": 54, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 807, + "left": 1167, + "height": 273, + "width": 191 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 704, + "left": 792, + "height": 247, + "width": 145 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 312, + "height": 306, + "width": 332 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 270, + "left": 0, + "height": 229, + "width": 295 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 266, + "left": 448, + "height": 129, + "width": 117 + }, + "classifications": [] + }] + }, { + "frameNumber": 55, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 1156, + "height": 267, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 706, + "left": 783, + "height": 247, + "width": 145 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 310, + "height": 304, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 260, + "left": 0, + "height": 231, + "width": 290 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 261, + "left": 435, + "height": 129, + "width": 118 + }, + "classifications": [] + }] + }, { + "frameNumber": 56, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 1148, + "height": 267, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 706, + "left": 784, + "height": 248, + "width": 147 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 650, + "left": 308, + "height": 304, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 257, + "left": 0, + "height": 234, + "width": 286 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 260, + "left": 428, + "height": 129, + "width": 118 + }, + "classifications": [] + }] + }, { + "frameNumber": 57, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 819, + "left": 1134, + "height": 261, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 705, + "left": 776, + "height": 248, + "width": 146 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 647, + "left": 303, + "height": 304, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 250, + "left": 0, + "height": 235, + "width": 283 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 255, + "left": 415, + "height": 128, + "width": 120 + }, + "classifications": [] + }] + }, { + "frameNumber": 58, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 822, + "left": 1127, + "height": 258, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 707, + "left": 775, + "height": 250, + "width": 138 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 648, + "left": 300, + "height": 304, + "width": 330 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 246, + "left": 0, + "height": 236, + "width": 279 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 250, + "left": 406, + "height": 128, + "width": 120 + }, + "classifications": [] + }] + }, { + "frameNumber": 59, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 825, + "left": 1120, + "height": 255, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 709.5, + "left": 780, + "height": 249, + "width": 124 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 645, + "left": 297.5, + "height": 306.5, + "width": 328 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 244, + "left": 11, + "height": 238, + "width": 265 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 248, + "left": 396, + "height": 127.5, + "width": 122 + }, + "classifications": [] + }] + }, { + "frameNumber": 60, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 828, + "left": 1108, + "height": 252, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 712, + "left": 785, + "height": 248, + "width": 110 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 642, + "left": 295, + "height": 309, + "width": 326 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 238, + "left": 24, + "height": 244, + "width": 248 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 246, + "left": 386, + "height": 127, + "width": 124 + }, + "classifications": [] + }] + }, { + "frameNumber": 61, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 832, + "left": 1099, + "height": 248, + "width": 191 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 716, + "left": 790, + "height": 241, + "width": 98 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 640, + "left": 279.5, + "height": 310, + "width": 340 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 233, + "left": 41, + "height": 243, + "width": 227 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 243, + "left": 379, + "height": 128, + "width": 123 + }, + "classifications": [] + }] + }, { + "frameNumber": 62, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 836, + "left": 1088, + "height": 244, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 894, + "left": 777, + "height": 63, + "width": 99 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 638, + "left": 264, + "height": 311, + "width": 354 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 227, + "left": 43, + "height": 234, + "width": 221 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 238, + "left": 367, + "height": 128, + "width": 123 + }, + "classifications": [] + }] + }, { + "frameNumber": 63, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 840, + "left": 1081, + "height": 240, + "width": 191 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 776, + "height": 60, + "width": 94 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 638, + "left": 256, + "height": 312, + "width": 359 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 226, + "left": 38, + "height": 225, + "width": 226 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 235, + "left": 361, + "height": 128, + "width": 123 + }, + "classifications": [] + }] + }, { + "frameNumber": 64, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 843, + "left": 1074, + "height": 237, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 860, + "left": 723, + "height": 85.5, + "width": 131 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 636.5, + "left": 250, + "height": 313, + "width": 363 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 222, + "left": 31, + "height": 222, + "width": 229 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 230, + "left": 361, + "height": 131, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 65, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 847, + "left": 1064, + "height": 233, + "width": 190 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 828, + "left": 670, + "height": 111, + "width": 168 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 635, + "left": 244, + "height": 314, + "width": 367 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 216, + "left": 29, + "height": 190, + "width": 228 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 227, + "left": 350, + "height": 131, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 66, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1054, + "height": 228, + "width": 192 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 813, + "left": 662, + "height": 116, + "width": 169 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 634.5, + "left": 239, + "height": 313, + "width": 369 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 214, + "left": 29, + "height": 163, + "width": 227 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 222, + "left": 343, + "height": 131, + "width": 115 + }, + "classifications": [] + }] + }, { + "frameNumber": 67, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1042, + "height": 228, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 808, + "left": 651, + "height": 122, + "width": 166 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 634, + "left": 234, + "height": 312, + "width": 371 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 209, + "left": 23, + "height": 161, + "width": 229 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 220, + "left": 337, + "height": 130, + "width": 110 + }, + "classifications": [] + }] + }, { + "frameNumber": 68, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 852, + "left": 1035, + "height": 228, + "width": 193 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 808, + "left": 651, + "height": 122, + "width": 156 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 224, + "height": 322, + "width": 377 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 203, + "left": 24, + "height": 163, + "width": 227 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 217, + "left": 329, + "height": 130, + "width": 108 + }, + "classifications": [] + }] + }, { + "frameNumber": 69, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 857, + "left": 1028, + "height": 223, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 802, + "left": 637, + "height": 127, + "width": 158 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 623, + "left": 220.667, + "height": 321.667, + "width": 379.333 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 203, + "left": 19, + "height": 153, + "width": 231 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 213, + "left": 325, + "height": 130, + "width": 108 + }, + "classifications": [] + }] + }, { + "frameNumber": 70, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 864, + "left": 1016, + "height": 216, + "width": 198 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 802, + "left": 629.5, + "height": 129.5, + "width": 153 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 623, + "left": 217.333, + "height": 321.333, + "width": 381.667 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 202.5, + "left": 19.5, + "height": 142.5, + "width": 228 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 212, + "left": 315, + "height": 124.5, + "width": 108 + }, + "classifications": [] + }] + }, { + "frameNumber": 71, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 864, + "left": 1009, + "height": 216, + "width": 198 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 802, + "left": 622, + "height": 132, + "width": 148 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 623, + "left": 214, + "height": 321, + "width": 384 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 202, + "left": 20, + "height": 132, + "width": 225 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 211, + "left": 305, + "height": 119, + "width": 108 + }, + "classifications": [] + }] + }, { + "frameNumber": 72, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 868, + "left": 994, + "height": 212, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 798, + "left": 610, + "height": 138, + "width": 165 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 620, + "left": 203, + "height": 323, + "width": 388 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 189, + "left": 16, + "height": 137, + "width": 227 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 212, + "left": 294, + "height": 114, + "width": 108 + }, + "classifications": [] + }] + }, { + "frameNumber": 73, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 873, + "left": 987, + "height": 207, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 787, + "left": 603, + "height": 151, + "width": 172 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 620, + "left": 203, + "height": 323, + "width": 389 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 183, + "left": 17, + "height": 126, + "width": 223 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 211, + "left": 286, + "height": 112, + "width": 109 + }, + "classifications": [] + }] + }, { + "frameNumber": 74, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 873, + "left": 980, + "height": 207, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 596, + "height": 150, + "width": 173 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 615, + "left": 195, + "height": 323, + "width": 389 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 173, + "left": 10, + "height": 123, + "width": 229 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 209, + "left": 278, + "height": 112, + "width": 107 + }, + "classifications": [] + }] + }, { + "frameNumber": 75, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 878, + "left": 968, + "height": 202, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 588, + "height": 143, + "width": 175 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 616, + "left": 188, + "height": 323, + "width": 389 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 168, + "left": 5, + "height": 113, + "width": 234 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 213, + "left": 276, + "height": 98, + "width": 98 + }, + "classifications": [] + }] + }, { + "frameNumber": 76, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 882, + "left": 961, + "height": 198, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 788, + "left": 582, + "height": 143, + "width": 175 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 614, + "left": 185, + "height": 326, + "width": 396 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 168, + "left": 0, + "height": 103, + "width": 237 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 217, + "left": 276, + "height": 86, + "width": 93 + }, + "classifications": [] + }] + }, { + "frameNumber": 77, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 882, + "left": 950, + "height": 198, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 768, + "left": 573, + "height": 174, + "width": 175 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 613, + "left": 182, + "height": 327, + "width": 399 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 161, + "left": 0, + "height": 112, + "width": 232 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 223, + "left": 282, + "height": 55, + "width": 76 + }, + "classifications": [] + }] + }, { + "frameNumber": 78, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 886, + "left": 944, + "height": 194, + "width": 199 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 763, + "left": 567, + "height": 179, + "width": 177 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 613, + "left": 182, + "height": 324, + "width": 399 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 158, + "left": 0, + "height": 118, + "width": 224 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 225, + "left": 301, + "height": 47, + "width": 49 + }, + "classifications": [] + }] + }, { + "frameNumber": 79, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 886, + "left": 936, + "height": 194, + "width": 199 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 760, + "left": 562, + "height": 181, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 611, + "left": 179, + "height": 324, + "width": 399 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 154, + "left": 0, + "height": 179, + "width": 218 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06er0y612emohrkf", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 225, + "left": 309, + "height": 41, + "width": 33 + }, + "classifications": [] + }] + }, { + "frameNumber": 80, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 925, + "height": 189, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 762, + "left": 555, + "height": 181, + "width": 174 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 608, + "left": 177, + "height": 327, + "width": 401 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 144, + "left": 0, + "height": 239, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1352, + "height": 202, + "width": 217 + }, + "classifications": [] + }] + }, { + "frameNumber": 81, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 920, + "height": 189, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 765, + "left": 552, + "height": 172, + "width": 164 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 602, + "left": 179, + "height": 328, + "width": 393 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 140, + "left": 0, + "height": 235, + "width": 208 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 341, + "left": 1347, + "height": 202, + "width": 217 + }, + "classifications": [] + }] + }, { + "frameNumber": 82, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 891, + "left": 910, + "height": 189, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 765, + "left": 544, + "height": 173, + "width": 174 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 602, + "left": 179, + "height": 327, + "width": 393 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 132, + "left": 0, + "height": 235, + "width": 208 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 342, + "left": 1336, + "height": 202, + "width": 217 + }, + "classifications": [] + }] + }, { + "frameNumber": 83, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 898, + "height": 184, + "width": 200 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 769, + "left": 541, + "height": 162, + "width": 169 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 598, + "left": 175, + "height": 327, + "width": 393 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 123, + "left": 0, + "height": 238, + "width": 208 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1331, + "height": 203, + "width": 217 + }, + "classifications": [] + }] + }, { + "frameNumber": 84, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 889, + "height": 184, + "width": 203 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 767, + "left": 537, + "height": 153, + "width": 168 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 595, + "left": 171, + "height": 327, + "width": 393 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 117, + "left": 0, + "height": 238, + "width": 208 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1326, + "height": 203, + "width": 217 + }, + "classifications": [] + }] + }, { + "frameNumber": 85, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 879, + "height": 184, + "width": 203 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 766, + "left": 531, + "height": 160, + "width": 162 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 585, + "left": 165, + "height": 332, + "width": 400 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 103, + "left": 0, + "height": 272, + "width": 210 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1318, + "height": 204, + "width": 215 + }, + "classifications": [] + }] + }, { + "frameNumber": 86, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 895, + "left": 868, + "height": 185, + "width": 205 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 759, + "left": 526, + "height": 159, + "width": 161 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 584, + "left": 164, + "height": 329, + "width": 400 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 94, + "left": 0, + "height": 274, + "width": 211 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 343, + "left": 1312, + "height": 204, + "width": 215 + }, + "classifications": [] + }] + }, { + "frameNumber": 87, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 855, + "height": 188, + "width": 206 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 755, + "left": 517, + "height": 159, + "width": 161 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 574, + "left": 210, + "height": 334, + "width": 349 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 78, + "left": 0, + "height": 281, + "width": 215 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 341, + "left": 1300, + "height": 204, + "width": 215 + }, + "classifications": [] + }] + }, { + "frameNumber": 88, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 849, + "height": 190, + "width": 206 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 753, + "left": 512, + "height": 163, + "width": 161 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 569, + "left": 207, + "height": 333, + "width": 352 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 71, + "left": 0, + "height": 281, + "width": 220 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1294, + "height": 204, + "width": 215 + }, + "classifications": [] + }] + }, { + "frameNumber": 89, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 839, + "height": 190, + "width": 209 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 746, + "left": 505, + "height": 166, + "width": 170 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 562, + "left": 203, + "height": 333, + "width": 352 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 62, + "left": 0, + "height": 281, + "width": 221 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1288, + "height": 204, + "width": 215 + }, + "classifications": [] + }] + }, { + "frameNumber": 90, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 832, + "height": 188, + "width": 203 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 747, + "left": 498, + "height": 143, + "width": 175 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 557, + "left": 196, + "height": 333, + "width": 352 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 47, + "left": 0, + "height": 283, + "width": 217 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1279, + "height": 205, + "width": 203 + }, + "classifications": [] + }] + }, { + "frameNumber": 91, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 892, + "left": 830, + "height": 188, + "width": 197 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 747, + "left": 495, + "height": 141, + "width": 174 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 549, + "left": 193, + "height": 340, + "width": 353 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 38, + "left": 0, + "height": 283, + "width": 217 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 335, + "left": 1272, + "height": 208, + "width": 207 + }, + "classifications": [] + }] + }, { + "frameNumber": 92, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 890, + "left": 826, + "height": 190, + "width": 189 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 487, + "height": 146, + "width": 145 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 546, + "left": 187, + "height": 334, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 27, + "left": 0, + "height": 285, + "width": 213 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 334, + "left": 1263, + "height": 208, + "width": 207 + }, + "classifications": [] + }] + }, { + "frameNumber": 93, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 813, + "height": 187, + "width": 196 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 743, + "left": 478, + "height": 143, + "width": 179 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 540, + "left": 187, + "height": 343, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 17, + "left": 0, + "height": 292, + "width": 213 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1258, + "height": 208, + "width": 198 + }, + "classifications": [] + }] + }, { + "frameNumber": 94, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 893.5, + "left": 812, + "height": 186.5, + "width": 186 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 735, + "left": 474, + "height": 149, + "width": 177 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 533, + "left": 184, + "height": 343, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 9, + "left": 0, + "height": 292, + "width": 213 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1251, + "height": 208, + "width": 198 + }, + "classifications": [] + }] + }, { + "frameNumber": 95, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 894, + "left": 811, + "height": 186, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 737, + "left": 465, + "height": 146, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 534, + "left": 181, + "height": 340, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 293, + "width": 209 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 336, + "left": 1240, + "height": 208, + "width": 192 + }, + "classifications": [] + }] + }, { + "frameNumber": 96, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 898, + "left": 809, + "height": 182, + "width": 171 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 460, + "height": 143, + "width": 181 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 528, + "left": 178, + "height": 340, + "width": 357 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 288, + "width": 210 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 336, + "left": 1234, + "height": 211, + "width": 195 + }, + "classifications": [] + }] + }, { + "frameNumber": 97, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 896, + "left": 805, + "height": 184, + "width": 165 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 740, + "left": 455, + "height": 138, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 524.5, + "left": 178, + "height": 343.5, + "width": 357.5 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 278, + "width": 213 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1223, + "height": 211, + "width": 195 + }, + "classifications": [] + }] + }, { + "frameNumber": 98, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 800, + "height": 187, + "width": 163 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 741, + "left": 449, + "height": 134, + "width": 176 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 521, + "left": 178, + "height": 347, + "width": 358 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 268, + "width": 211 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 337, + "left": 1219, + "height": 211, + "width": 195 + }, + "classifications": [] + }] + }, { + "frameNumber": 99, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 893, + "left": 795, + "height": 187, + "width": 160 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 739, + "left": 449, + "height": 136, + "width": 171 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 515, + "left": 178, + "height": 345, + "width": 359 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 266, + "width": 215 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 339, + "left": 1214, + "height": 211, + "width": 195 + }, + "classifications": [] + }] + }, { + "frameNumber": 100, + "classifications": [], + "objects": [{ + "featureId": "ckqcx1d9x06em0y618b90atyy", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 898, + "left": 786, + "height": 182, + "width": 158 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06en0y612vo2feu6", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 738, + "left": 467, + "height": 136, + "width": 146 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06ep0y617a2f5wbs", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": false, + "bbox": { + "top": 515, + "left": 178, + "height": 345, + "width": 359 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06eq0y6136uoa1xg", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 0, + "left": 0, + "height": 256, + "width": 217 + }, + "classifications": [] + }, { + "featureId": "ckqcx1d9x06es0y61gvx60aqk", + "schemaId": "ckqcx1d8h06dr0y61fqb87ecf", + "title": "Jellyfish", + "value": "jellyfish", + "color": "#a23030", + "keyframe": true, + "bbox": { + "top": 338, + "left": 1203, + "height": 211, + "width": 195 + }, + "classifications": [] + }] + }], "Created By": "msokoloff+11@labelbox.com", "Project Name": "Sample Video Project", "Created At": "2021-06-25T22:38:27.000Z", diff --git a/libs/labelbox/tests/data/assets/ndjson/video_import.json b/libs/labelbox/tests/data/assets/ndjson/video_import.json index 8199458cf..59a1c616d 100644 --- a/libs/labelbox/tests/data/assets/ndjson/video_import.json +++ b/libs/labelbox/tests/data/assets/ndjson/video_import.json @@ -1,210 +1,166 @@ -[ - { - "answer": { - "schemaId": "ckrb1sfl8099g0y91cxbd5ftb" - }, - "schemaId": "ckrb1sfjx099a0y914hl319ie", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", - "frames": [ - { - "start": 30, - "end": 35 - }, - { - "start": 50, - "end": 51 - } - ] +[{ + "answer": { + "schemaId": "ckrb1sfl8099g0y91cxbd5ftb" }, - { - "answer": [ - { - "schemaId": "ckrb1sfl8099e0y919v260awv" - } - ], - "schemaId": "ckrb1sfkn099c0y910wbo0p1a", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", - "frames": [ - { - "start": 0, - "end": 5 - } - ] + "schemaId": "ckrb1sfjx099a0y914hl319ie", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "answer": "a value", - "schemaId": "ckrb1sfkn099c0y910wbo0p1a", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "90e2ecf7-c19c-47e6-8cdb-8867e1b9d88c" + "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", + "frames": [{ + "start": 30, + "end": 35 + }, { + "start": 50, + "end": 51 + }] +}, { + "answer": [{ + "schemaId": "ckrb1sfl8099e0y919v260awv" + }], + "schemaId": "ckrb1sfkn099c0y910wbo0p1a", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "schemaId": "cl5islwg200gfci6g0oitaypu", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "6f7c835a-0139-4896-b73f-66a6baa89e94", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "line": [ - { - "x": 10.0, - "y": 10.0 - }, - { - "x": 100.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - }, - { - "frame": 5, - "line": [ - { - "x": 15.0, - "y": 10.0 - }, - { - "x": 50.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - } - ] - }, - { - "keyframes": [ - { - "frame": 8, - "line": [ - { - "x": 100.0, - "y": 10.0 - }, - { - "x": 50.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - } - ] - } - ] + "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", + "frames": [{ + "start": 0, + "end": 5 + }] +}, { + "answer": "a value", + "schemaId": "ckrb1sfkn099c0y910wbo0p1a", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "90e2ecf7-c19c-47e6-8cdb-8867e1b9d88c" +}, { + "classifications": [], + "schemaId": + "cl5islwg200gfci6g0oitaypu", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": + "6f7c835a-0139-4896-b73f-66a6baa89e94", + "segments": [{ + "keyframes": [{ + "frame": 1, + "line": [{ + "x": 10.0, + "y": 10.0 + }, { + "x": 100.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }, { + "frame": 5, + "line": [{ + "x": 15.0, + "y": 10.0 + }, { + "x": 50.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 8, + "line": [{ + "x": 100.0, + "y": 10.0 + }, { + "x": 50.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }] + }] +}, { + "classifications": [], + "schemaId": + "cl5it7ktp00i5ci6gf80b1ysd", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "schemaId": "cl5it7ktp00i5ci6gf80b1ysd", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f963be22-227b-4efe-9be4-2738ed822216", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "point": { - "x": 10.0, - "y": 10.0 - }, - "classifications": [] - } - ] + "uuid": + "f963be22-227b-4efe-9be4-2738ed822216", + "segments": [{ + "keyframes": [{ + "frame": 1, + "point": { + "x": 10.0, + "y": 10.0 }, - { - "keyframes": [ - { - "frame": 5, - "point": { - "x": 50.0, - "y": 50.0 - }, - "classifications": [] - }, - { - "frame": 10, - "point": { - "x": 10.0, - "y": 50.0 - }, - "classifications": [] - } - ] - } - ] + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 5, + "point": { + "x": 50.0, + "y": 50.0 + }, + "classifications": [] + }, { + "frame": 10, + "point": { + "x": 10.0, + "y": 50.0 + }, + "classifications": [] + }] + }] +}, { + "classifications": [], + "schemaId": + "cl5iw0roz00lwci6g5jni62vs", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "schemaId": "cl5iw0roz00lwci6g5jni62vs", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "bbox": { - "top": 10.0, - "left": 5.0, - "height": 100.0, - "width": 150.0 - }, - "classifications": [] - }, - { - "frame": 5, - "bbox": { - "top": 30.0, - "left": 5.0, - "height": 50.0, - "width": 150.0 - }, - "classifications": [] - } - ] + "uuid": + "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", + "segments": [{ + "keyframes": [{ + "frame": 1, + "bbox": { + "top": 10.0, + "left": 5.0, + "height": 100.0, + "width": 150.0 + }, + "classifications": [] + }, { + "frame": 5, + "bbox": { + "top": 30.0, + "left": 5.0, + "height": 50.0, + "width": 150.0 + }, + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 10, + "bbox": { + "top": 300.0, + "left": 200.0, + "height": 400.0, + "width": 150.0 }, - { - "keyframes": [ - { - "frame": 10, - "bbox": { - "top": 300.0, - "left": 200.0, - "height": 400.0, - "width": 150.0 - }, - "classifications": [] - } - ] - } - ] - } -] \ No newline at end of file + "classifications": [] + }] + }] +}] \ No newline at end of file From c2f459266c0e247e246ce392dd24211add9cb530 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 00:35:19 -0500 Subject: [PATCH 19/34] converted to self --- .../data/annotation_types/data/raster.py | 18 +++++++++--------- .../data/annotation_types/data/text.py | 14 +++++++------- .../data/annotation_types/data/tiled_image.py | 8 ++++---- .../data/annotation_types/data/video.py | 14 +++++++------- .../labelbox/data/annotation_types/feature.py | 1 - .../data/annotation_types/ner/text_entity.py | 10 +++++----- .../labelbox/data/annotation_types/video.py | 9 ++++----- libs/labelbox/src/labelbox/data/mixins.py | 1 - .../data/serialization/labelbox_v1/feature.py | 8 ++++---- .../labelbox/data/serialization/ndjson/base.py | 12 ++++++------ .../serialization/ndjson/classification.py | 6 +++--- .../src/labelbox/schema/bulk_import_request.py | 6 +++--- .../labelbox/schema/send_to_annotate_params.py | 8 ++++---- 13 files changed, 56 insertions(+), 59 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py index 15ae0aa42..50c7f4947 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/raster.py @@ -159,13 +159,13 @@ def create_url(self, signer: Callable[[bytes], str]) -> str: return self.url @model_validator(mode="after") - def validate_args(cls, values): - file_path = cls.file_path - im_bytes = cls.im_bytes - url = cls.url - arr = cls.arr - uid = cls.uid - global_key = cls.global_key + def validate_args(self, values): + file_path = self.file_path + im_bytes = self.im_bytes + url = self.url + arr = self.arr + uid = self.uid + global_key = self.global_key if uid == file_path == im_bytes == url == global_key == None and arr is None: raise ValueError( "One of `file_path`, `im_bytes`, `url`, `uid`, `global_key` or `arr` required." @@ -178,8 +178,8 @@ def validate_args(cls, values): elif len(arr.shape) != 3: raise ValueError( "unsupported image format. Must be 3D ([H,W,C])." - f"Use {cls.__name__}.from_2D_arr to construct from 2D") - return cls + f"Use {self.__name__}.from_2D_arr to construct from 2D") + return self def __repr__(self) -> str: symbol_or_none = lambda data: '...' if data is not None else None diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py index ed57dfefa..20624c161 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/text.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/text.py @@ -92,17 +92,17 @@ def create_url(self, signer: Callable[[bytes], str]) -> None: return self.url @model_validator(mode="after") - def validate_date(cls, values): - file_path = cls.file_path - text = cls.text - url = cls.url - uid = cls.uid - global_key = cls.global_key + def validate_date(self, values): + file_path = self.file_path + text = self.text + url = self.url + uid = self.uid + global_key = self.global_key if uid == file_path == text == url == global_key == None: raise ValueError( "One of `file_path`, `text`, `uid`, `global_key` or `url` required." ) - return cls + return self def __repr__(self) -> str: return f"TextData(file_path={self.file_path}," \ diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py index d06f4fc09..5d3561ceb 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/tiled_image.py @@ -67,9 +67,9 @@ def validate_bounds_not_equal(cls, bounds): #validate bounds are within lat,lng range if they are EPSG4326 @model_validator(mode="after") - def validate_bounds_lat_lng(cls): - epsg = cls.epsg - bounds = cls.bounds + def validate_bounds_lat_lng(self): + epsg = self.epsg + bounds = self.bounds if epsg == EPSG.EPSG4326: for bound in bounds: @@ -79,7 +79,7 @@ def validate_bounds_lat_lng(cls): raise ValueError(f"Invalid lat/lng bounds. Found {bounds}. " f"lat must be in {VALID_LAT_RANGE}. " f"lng must be in {VALID_LNG_RANGE}.") - return cls + return self class TileLayer(BaseModel): diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py index ba74bd4f0..5d7804860 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/video.py @@ -151,18 +151,18 @@ def frames_to_video(self, return file_path @model_validator(mode="after") - def validate_data(cls): - file_path = cls.file_path - url = cls.url - frames = cls.frames - uid = cls.uid - global_key = cls.global_key + def validate_data(self): + file_path = self.file_path + url = self.url + frames = self.frames + uid = self.uid + global_key = self.global_key if uid == file_path == frames == url == global_key == None: raise ValueError( "One of `file_path`, `frames`, `uid`, `global_key` or `url` required." ) - return cls + return self def __repr__(self) -> str: return f"VideoData(file_path={self.file_path}," \ diff --git a/libs/labelbox/src/labelbox/data/annotation_types/feature.py b/libs/labelbox/src/labelbox/data/annotation_types/feature.py index 5b708f595..4224296b6 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/feature.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/feature.py @@ -1,7 +1,6 @@ from typing import Optional from pydantic import BaseModel, model_validator, model_serializer from .types import Cuid -from labelbox.pydantic_serializers import _feature_serializer class FeatureSchema(BaseModel): diff --git a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py index 9db944312..60764f759 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/ner/text_entity.py @@ -10,10 +10,10 @@ class TextEntity(BaseModel): extra: Dict[str, Any] = {} @model_validator(mode="after") - def validate_start_end(cls, values): - if hasattr(cls, 'start') and hasattr(cls, 'end'): - if (isinstance(cls.start, int) and - cls.start > cls.end): + def validate_start_end(self, values): + if hasattr(self, 'start') and hasattr(self, 'end'): + if (isinstance(self.start, int) and + self.start > self.end): raise ValueError( "Location end must be greater or equal to start") - return cls + return self diff --git a/libs/labelbox/src/labelbox/data/annotation_types/video.py b/libs/labelbox/src/labelbox/data/annotation_types/video.py index 8b06949e9..79a14ec2d 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/video.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/video.py @@ -8,7 +8,6 @@ from labelbox.data.mixins import ConfidenceNotSupportedMixin, CustomMetricsNotSupportedMixin from labelbox.utils import _CamelCaseMixin, is_valid_uri from pydantic import model_validator, BaseModel, field_validator, model_serializer, Field, ConfigDict, AliasChoices -from labelbox.pydantic_serializers import _feature_serializer class VideoClassificationAnnotation(ClassificationAnnotation): @@ -96,12 +95,12 @@ class MaskFrame(_CamelCaseMixin, BaseModel): model_config = ConfigDict(populate_by_name=True) @model_validator(mode="after") - def validate_args(cls, values): - im_bytes = cls.im_bytes - instance_uri = cls.instance_uri + def validate_args(self, values): + im_bytes = self.im_bytes + instance_uri = self.instance_uri if im_bytes == instance_uri == None: raise ValueError("One of `instance_uri`, `im_bytes` required.") - return cls + return self @field_validator("instance_uri") def validate_uri(cls, v): diff --git a/libs/labelbox/src/labelbox/data/mixins.py b/libs/labelbox/src/labelbox/data/mixins.py index c6466279d..d8bc78de0 100644 --- a/libs/labelbox/src/labelbox/data/mixins.py +++ b/libs/labelbox/src/labelbox/data/mixins.py @@ -5,7 +5,6 @@ from labelbox.exceptions import ConfidenceNotSupportedException, CustomMetricsNotSupportedException from warnings import warn -from labelbox.pydantic_serializers import _feature_serializer class ConfidenceMixin(BaseModel): diff --git a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py index a68a666a7..ed931dd77 100644 --- a/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py +++ b/libs/labelbox/src/labelbox/data/serialization/labelbox_v1/feature.py @@ -14,10 +14,10 @@ class LBV1Feature(BaseModel): model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) @model_validator(mode = "after") - def check_ids(cls, values): - if values.value is None: - values.value = values.title - return values + def check_ids(self, values): + if self.value is None: + self.value = self.title + return self @model_serializer(mode = "wrap") def serialize_model(self, handler): diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index 7cb8fed3b..9d18f2ec5 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -23,10 +23,10 @@ class DataRow(_CamelCaseMixin): @model_validator(mode="after") - def must_set_one(cls): - if not is_exactly_one_set(cls.id, cls.global_key): + def must_set_one(self): + if not is_exactly_one_set(self.id, self.global_key): raise ValueError("Must set either id or global_key") - return cls + return self class NDJsonBase(_CamelCaseMixin): @@ -42,7 +42,7 @@ class NDAnnotation(NDJsonBase): unit: Optional[str] = None @model_validator(mode="after") - def must_set_one(cls): - if (not hasattr(cls, "schema_id") or cls.schema_id is None) and (not hasattr(cls, "name") or cls.name is None): + def must_set_one(self): + if (not hasattr(self, "schema_id") or self.schema_id is None) and (not hasattr(self, "name") or self.name is None): raise ValueError("Schema id or name are not set. Set either one.") - return cls + return self diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index 4c04c9c09..299f49da7 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -21,10 +21,10 @@ class NDAnswer(ConfidenceMixin, CustomMetricsMixin): model_config = ConfigDict(populate_by_name = True, alias_generator = to_camel) @model_validator(mode="after") - def must_set_one(cls): - if (not hasattr(cls, "schema_id") or cls.schema_id is None) and (not hasattr(cls, "name") or cls.name is None): + def must_set_one(self): + if (not hasattr(self, "schema_id") or self.schema_id is None) and (not hasattr(self, "name") or self.name is None): raise ValueError("Schema id or name are not set. Set either one.") - return cls + return self @model_serializer(mode="wrap") def serialize_model(self, handler): diff --git a/libs/labelbox/src/labelbox/schema/bulk_import_request.py b/libs/labelbox/src/labelbox/schema/bulk_import_request.py index 9166d6078..6e65aab58 100644 --- a/libs/labelbox/src/labelbox/schema/bulk_import_request.py +++ b/libs/labelbox/src/labelbox/schema/bulk_import_request.py @@ -623,11 +623,11 @@ class NDFeatureSchema(BaseModel): name: Optional[str] = None @model_validator(mode="after") - def must_set_one(cls): - if cls.schemaId is None and cls.name is None: + def most_set_one(self): + if self.schemaId is None and self.name is None: raise ValueError( "Must set either schemaId or name for all feature schemas") - return cls + return self class NDBase(NDFeatureSchema): diff --git a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py index 52d40ea57..f3636e14d 100644 --- a/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py +++ b/libs/labelbox/src/labelbox/schema/send_to_annotate_params.py @@ -42,16 +42,16 @@ class SendToAnnotateFromCatalogParams(BaseModel): batch_priority: Optional[int] = 5 @model_validator(mode="after") - def check_project_id_or_model_run_id(cls): - if not cls.source_model_run_id and not cls.source_project_id: + def check_project_id_or_model_run_id(self): + if not self.source_model_run_id and not self.source_project_id: raise ValueError( 'Either source_project_id or source_model_id are required' ) - if cls.source_model_run_id and cls.source_project_id: + if self.source_model_run_id and self.source_project_id: raise ValueError( 'Provide only a source_project_id or source_model_id not both' ) - return cls + return self class SendToAnnotateFromModelParams(TypedDict): """ From d8acc76d58da576e1b9911de056ffe60da7f85cf Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 08:09:55 -0500 Subject: [PATCH 20/34] fixed bad tests --- .../labelbox/data/annotation_types/feature.py | 4 ---- .../labelbox/data/annotation_types/label.py | 1 - .../data/serialization/ndjson/label.py | 5 ----- .../src/labelbox/schema/data_row_metadata.py | 20 ++++++++++++++++++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/feature.py b/libs/labelbox/src/labelbox/data/annotation_types/feature.py index 4224296b6..836817aeb 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/feature.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/feature.py @@ -19,7 +19,3 @@ def must_set_one(self): "Must set either feature_schema_id or name for all feature schemas" ) return self - @model_serializer(mode="wrap") - def model_serializer(self, handler): - res = handler(self) - return _feature_serializer(res) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/label.py b/libs/labelbox/src/labelbox/data/annotation_types/label.py index 9cd3dce05..f51812b3e 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/label.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/label.py @@ -18,7 +18,6 @@ from .video import VideoObjectAnnotation, VideoMaskAnnotation from ..ontology import get_feature_schema_lookup from pydantic import BaseModel, field_validator, model_serializer -from labelbox.pydantic_serializers import _feature_serializer DataType = Union[VideoData, ImageData, TextData, TiledImageData, AudioData, ConversationData, DicomData, DocumentData, HTMLData, diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index ddfa1c836..d12cd57d0 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -24,7 +24,6 @@ from .relationship import NDRelationship from .base import DataRow from pydantic import BaseModel, ConfigDict, model_serializer, ValidationError -from labelbox.pydantic_serializers import _feature_serializer from .base import subclass_registry, SubclassRegistryBase, NDAnnotation from pydantic_core import PydanticUndefined from pydantic.alias_generators import to_camel @@ -69,10 +68,6 @@ def __init__(self, **kwargs): break kwargs["annotations"][index] = annotation super().__init__(**kwargs) - - @model_serializer(mode="wrap") - def serialize_model(self, handler): - return _feature_serializer(handler(self)) class _Relationship(BaseModel): """This object holds information about the relationship""" diff --git a/libs/labelbox/src/labelbox/schema/data_row_metadata.py b/libs/labelbox/src/labelbox/schema/data_row_metadata.py index 3fc004c4a..cb02c32f8 100644 --- a/libs/labelbox/src/labelbox/schema/data_row_metadata.py +++ b/libs/labelbox/src/labelbox/schema/data_row_metadata.py @@ -10,7 +10,7 @@ from labelbox.schema.identifiables import DataRowIdentifiers, UniqueIds from labelbox.schema.identifiable import UniqueId, GlobalKey -from pydantic import BaseModel, Field, StringConstraints, conlist +from pydantic import BaseModel, Field, StringConstraints, conlist, ConfigDict, model_serializer from labelbox.schema.ontology import SchemaId from labelbox.utils import _CamelCaseMixin, format_iso_datetime, format_iso_from_string @@ -95,6 +95,24 @@ class _UpsertBatchDataRowMetadata(_CamelCaseMixin): class _DeleteBatchDataRowMetadata(_CamelCaseMixin): data_row_identifier: Union[UniqueId, GlobalKey] schema_ids: List[SchemaId] + + model_config = ConfigDict(arbitrary_types_allowed=True) + + @model_serializer(mode="wrap") + def model_serializer(self, handler): + res = handler(self) + if 'data_row_identifier' in res.keys(): + key = 'data_row_identifier' + id_type_key = 'id_type' + else: + key = 'dataRowIdentifier' + id_type_key = 'idType' + data_row_identifier = res.pop(key) + res[key] = { + "id": data_row_identifier.key, + id_type_key: data_row_identifier.id_type + } + return res _BatchInputs = Union[List[_UpsertBatchDataRowMetadata], From 699d39259fce682e823c1f9bcd80a416f9002a5a Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 08:26:28 -0500 Subject: [PATCH 21/34] added notes --- .../data/serialization/ndjson/label.py | 11 +- .../data/serialization/ndjson/objects.py | 4 - .../assets/ndjson/video_import_name_only.json | 362 ++++++++---------- .../data/serialization/ndjson/test_video.py | 44 +-- 4 files changed, 191 insertions(+), 230 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index d12cd57d0..8c69b8667 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -39,6 +39,13 @@ class NDLabel(BaseModel): annotations: List[SubclassRegistryBase] def __init__(self, **kwargs): + # NOTE: Deserialization of subclasses in pydantic is difficult, see here https://blog.devgenius.io/deserialize-child-classes-with-pydantic-that-gonna-work-784230e1cf83 + # Below implements the subclass registry as mentioned in the article. The python dicts we pass in can be missing certain fields + # we essentially have to infer the type against all sub classes that have the SubclasssRegistryBase inheritance. + # It works by checking if the keys of our annotations we are missing in matches any required subclass. + # More keys are prioritized over less keys (closer match). This is used when importing json to our base models not a lot of customer workflows + # depend on this method but this works for all our existing tests with the bonus of added validation. (no subclass found it throws an error) + # Previous strategies hacked but dont work for pydantic V2 for index in range(len(kwargs["annotations"])): annotation = kwargs["annotations"][index] if isinstance(annotation, dict): @@ -47,7 +54,7 @@ def __init__(self, **kwargs): for name, subclass in subclass_registry.items(): subclass: BaseModel = subclass - # NDJSON has all required keys for a subclass. Serialize to first subclass. + # Get all required keys from subclass annotation_keys = [] for k, field in subclass.model_fields.items(): # must account for alias @@ -59,6 +66,8 @@ def __init__(self, **kwargs): # Sort by subclass that has the most keys key_subclass_combos = dict(sorted(key_subclass_combos.items(), key = lambda x : len(x[1]), reverse=True)) + + # Choose the key that our dict we are passing in has all the keys to match for subclass, key_subclass_combo in key_subclass_combos.items(): check_required_keys = all(key in list(item_annotation_keys) for key in key_subclass_combo) if check_required_keys: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index fd90b24eb..286cb2e24 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -772,10 +772,6 @@ def lookup_object( ) return result - -# NOTE: Deserialization of subclasses in pydantic is a known PIA, see here https://blog.devgenius.io/deserialize-child-classes-with-pydantic-that-gonna-work-784230e1cf83 -# I could implement the registry approach suggested there, but I found that if I list subclass (that has more attributes) before the parent class, it works -# This is a bit of a hack, but it works for now NDEntityType = Union[NDConversationEntity, NDTextEntity] NDObjectType = Union[NDLine, NDPolygon, NDPoint, NDDocumentRectangle, NDRectangle, NDMask, NDEntityType, NDDocumentEntity] diff --git a/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json b/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json index 1210b6059..b82602f46 100644 --- a/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json +++ b/libs/labelbox/tests/data/assets/ndjson/video_import_name_only.json @@ -1,210 +1,166 @@ -[ - { - "answer": { - "name": "answer 1" - }, - "name": "question 1", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", - "frames": [ - { - "start": 30, - "end": 35 - }, - { - "start": 50, - "end": 51 - } - ] +[{ + "answer": { + "name": "answer 1" }, - { - "answer": [ - { - "name": "answer 2" - } - ], - "name": "question 2", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", - "frames": [ - { - "start": 0, - "end": 5 - } - ] + "name": "question 1", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "answer": "a value", - "name": "question 3", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "e5f32456-bd67-4520-8d3b-cbeb2204bad3" + "uuid": "f6879f59-d2b5-49c2-aceb-d9e8dc478673", + "frames": [{ + "start": 30, + "end": 35 + }, { + "start": 50, + "end": 51 + }] +}, { + "answer": [{ + "name": "answer 2" + }], + "name": "question 2", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "name": "segment 1", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "6f7c835a-0139-4896-b73f-66a6baa89e94", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "line": [ - { - "x": 10.0, - "y": 10.0 - }, - { - "x": 100.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - }, - { - "frame": 5, - "line": [ - { - "x": 15.0, - "y": 10.0 - }, - { - "x": 50.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - } - ] - }, - { - "keyframes": [ - { - "frame": 8, - "line": [ - { - "x": 100.0, - "y": 10.0 - }, - { - "x": 50.0, - "y": 100.0 - }, - { - "x": 50.0, - "y": 30.0 - } - ], - "classifications": [] - } - ] - } - ] + "uuid": "d009925d-91a3-4f67-abd9-753453f5a584", + "frames": [{ + "start": 0, + "end": 5 + }] +}, { + "answer": "a value", + "name": "question 3", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": "e5f32456-bd67-4520-8d3b-cbeb2204bad3" +}, { + "classifications": [], + "name": + "segment 1", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" + }, + "uuid": + "6f7c835a-0139-4896-b73f-66a6baa89e94", + "segments": [{ + "keyframes": [{ + "frame": 1, + "line": [{ + "x": 10.0, + "y": 10.0 + }, { + "x": 100.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }, { + "frame": 5, + "line": [{ + "x": 15.0, + "y": 10.0 + }, { + "x": 50.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 8, + "line": [{ + "x": 100.0, + "y": 10.0 + }, { + "x": 50.0, + "y": 100.0 + }, { + "x": 50.0, + "y": 30.0 + }], + "classifications": [] + }] + }] +}, { + "classifications": [], + "name": + "segment 2", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "name": "segment 2", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "f963be22-227b-4efe-9be4-2738ed822216", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "point": { - "x": 10.0, - "y": 10.0 - }, - "classifications": [] - } - ] + "uuid": + "f963be22-227b-4efe-9be4-2738ed822216", + "segments": [{ + "keyframes": [{ + "frame": 1, + "point": { + "x": 10.0, + "y": 10.0 }, - { - "keyframes": [ - { - "frame": 5, - "point": { - "x": 50.0, - "y": 50.0 - }, - "classifications": [] - }, - { - "frame": 10, - "point": { - "x": 10.0, - "y": 50.0 - }, - "classifications": [] - } - ] - } - ] + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 5, + "point": { + "x": 50.0, + "y": 50.0 + }, + "classifications": [] + }, { + "frame": 10, + "point": { + "x": 10.0, + "y": 50.0 + }, + "classifications": [] + }] + }] +}, { + "classifications": [], + "name": + "segment 3", + "dataRow": { + "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" }, - { - "classifications": [], - "name": "segment 3", - "dataRow": { - "id": "ckrb1sf1i1g7i0ybcdc6oc8ct" - }, - "uuid": "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", - "segments": [ - { - "keyframes": [ - { - "frame": 1, - "bbox": { - "top": 10.0, - "left": 5.0, - "height": 100.0, - "width": 150.0 - }, - "classifications": [] - }, - { - "frame": 5, - "bbox": { - "top": 30.0, - "left": 5.0, - "height": 50.0, - "width": 150.0 - }, - "classifications": [] - } - ] + "uuid": + "13b2ee0e-2355-4336-8b83-d74d09e3b1e7", + "segments": [{ + "keyframes": [{ + "frame": 1, + "bbox": { + "top": 10.0, + "left": 5.0, + "height": 100.0, + "width": 150.0 + }, + "classifications": [] + }, { + "frame": 5, + "bbox": { + "top": 30.0, + "left": 5.0, + "height": 50.0, + "width": 150.0 + }, + "classifications": [] + }] + }, { + "keyframes": [{ + "frame": 10, + "bbox": { + "top": 300.0, + "left": 200.0, + "height": 400.0, + "width": 150.0 }, - { - "keyframes": [ - { - "frame": 10, - "bbox": { - "top": 300.0, - "left": 200.0, - "height": 400.0, - "width": 150.0 - }, - "classifications": [] - } - ] - } - ] - } -] \ No newline at end of file + "classifications": [] + }] + }] +}] \ No newline at end of file diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_video.py b/libs/labelbox/tests/data/serialization/ndjson/test_video.py index ff74db7c1..4b90a8060 100644 --- a/libs/labelbox/tests/data/serialization/ndjson/test_video.py +++ b/libs/labelbox/tests/data/serialization/ndjson/test_video.py @@ -437,29 +437,38 @@ def test_video_classification_frameline(): 'classifications': [], 'segments': [{ 'keyframes': [{ + 'frame': + 13, + 'line': [{ + 'x': 8.0, + 'y': 10.0, + }, { + 'x': 10.0, + 'y': 9.0, + }], 'classifications': [{ 'name': 'radio_question_nested', 'answer': { + 'name': + 'first_radio_question', 'classifications': [{ 'name': 'sub_question_radio', 'answer': [{ 'name': 'sub_answer' }] - }], - 'name': - 'first_radio_question' + }] } - }], + }] + }, { 'frame': - 13, + 15, 'line': [{ - 'x': 8.0, - 'y': 10.0, + 'x': 18.0, + 'y': 20.0, }, { - 'x': 10.0, - 'y': 9.0, - }] - }, { + 'x': 20.0, + 'y': 19.0, + }], 'classifications': [{ 'name': 'nested_checklist_question', @@ -473,18 +482,8 @@ def test_video_classification_frameline(): } }] }] - }], - 'frame': - 15, - 'line': [{ - 'x': 18.0, - 'y': 20.0, - }, { - 'x': 20.0, - 'y': 19.0, }] }, { - 'classifications': [], 'frame': 19, 'line': [{ 'x': 28.0, @@ -492,7 +491,8 @@ def test_video_classification_frameline(): }, { 'x': 30.0, 'y': 29.0, - }] + }], + 'classifications': [] }] }] }] From 61ec600265d559318bf757256cfc4b23be378692 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 08:55:56 -0500 Subject: [PATCH 22/34] fixed last test --- .../src/labelbox/data/annotation_types/metrics/scalar.py | 2 +- libs/labelbox/tests/data/annotation_types/test_metrics.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 04279892a..20914753f 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -31,7 +31,7 @@ class ScalarMetric(BaseMetric): """ metric_name: Optional[str] = None value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] - aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN + aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN.value @field_validator('metric_name') def validate_metric_name(cls, name: Union[str, None]): diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index 7bc7c78ba..f7b3cc7dd 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -19,11 +19,15 @@ def test_legacy_scalar_metric(): 'uid': 'ckrmd9q8g000009mg6vej7hzg', }, 'annotations': [{ + 'aggregation': 'ARITHMETIC_MEAN', 'value': 10.0, 'extra': {}, }], 'extra': {}, } + from pprint import pprint + pprint(label.model_dump(exclude_none=True)) + pprint(expected) assert label.model_dump(exclude_none=True) == expected From 85ee809b4b0990c218ee8f8a3d03e11bf48c08e7 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:18:12 -0500 Subject: [PATCH 23/34] fixed last test --- .../src/labelbox/data/annotation_types/metrics/scalar.py | 2 +- libs/labelbox/tests/data/annotation_types/test_metrics.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 20914753f..04279892a 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -31,7 +31,7 @@ class ScalarMetric(BaseMetric): """ metric_name: Optional[str] = None value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] - aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN.value + aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN @field_validator('metric_name') def validate_metric_name(cls, name: Union[str, None]): diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index f7b3cc7dd..ebba1cb93 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -19,15 +19,12 @@ def test_legacy_scalar_metric(): 'uid': 'ckrmd9q8g000009mg6vej7hzg', }, 'annotations': [{ - 'aggregation': 'ARITHMETIC_MEAN', + 'aggregation': ScalarMetricAggregation.ARITHMETIC_MEAN, 'value': 10.0, 'extra': {}, }], 'extra': {}, } - from pprint import pprint - pprint(label.model_dump(exclude_none=True)) - pprint(expected) assert label.model_dump(exclude_none=True) == expected From 83fe5431e1fe7a12846d3727faca33d3ec52df86 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Mon, 26 Aug 2024 16:07:08 -0700 Subject: [PATCH 24/34] Fix LabelingService classes --- libs/labelbox/src/labelbox/schema/labeling_service.py | 7 ++----- .../src/labelbox/schema/labeling_service_dashboard.py | 7 ++----- libs/labelbox/src/labelbox/schema/search_filters.py | 5 ++--- libs/labelbox/tests/data/annotation_types/test_metrics.py | 3 +++ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/labeling_service.py b/libs/labelbox/src/labelbox/schema/labeling_service.py index 41e3e559b..0972e80d2 100644 --- a/libs/labelbox/src/labelbox/schema/labeling_service.py +++ b/libs/labelbox/src/labelbox/schema/labeling_service.py @@ -5,7 +5,7 @@ from labelbox.exceptions import LabelboxError, ResourceNotFoundError -from labelbox.pydantic_compat import BaseModel, Field +from pydantic import BaseModel, Field from labelbox.utils import _CamelCaseMixin from labelbox.schema.labeling_service_dashboard import LabelingServiceDashboard from labelbox.schema.labeling_service_status import LabelingServiceStatus @@ -13,7 +13,7 @@ Cuid = Annotated[str, Field(min_length=25, max_length=25)] -class LabelingService(BaseModel): +class LabelingService(_CamelCaseMixin): """ Labeling service for a project. This is a service that can be requested to label data for a project. """ @@ -31,9 +31,6 @@ def __init__(self, **kwargs): raise RuntimeError( "Please enable experimental in client to use LabelingService") - class Config(_CamelCaseMixin.Config): - ... - @classmethod def start(cls, client, project_id: Cuid) -> 'LabelingService': """ diff --git a/libs/labelbox/src/labelbox/schema/labeling_service_dashboard.py b/libs/labelbox/src/labelbox/schema/labeling_service_dashboard.py index e640ed848..b49c7fe8e 100644 --- a/libs/labelbox/src/labelbox/schema/labeling_service_dashboard.py +++ b/libs/labelbox/src/labelbox/schema/labeling_service_dashboard.py @@ -4,7 +4,7 @@ from labelbox.exceptions import ResourceNotFoundError from labelbox.pagination import PaginatedCollection -from labelbox.pydantic_compat import BaseModel, root_validator, Field +from pydantic import BaseModel, root_validator, Field from labelbox.schema.search_filters import SearchFilter, build_search_filter from labelbox.utils import _CamelCaseMixin from .ontology_kind import EditorTaskType @@ -39,7 +39,7 @@ class LabelingServiceDashboardTags(BaseModel): type: str -class LabelingServiceDashboard(BaseModel): +class LabelingServiceDashboard(_CamelCaseMixin): """ Represent labeling service data for a project @@ -105,9 +105,6 @@ def service_type(self): return sentence_case(self.media_type.value) - class Config(_CamelCaseMixin.Config): - ... - @classmethod def get(cls, client, project_id: str) -> 'LabelingServiceDashboard': """ diff --git a/libs/labelbox/src/labelbox/schema/search_filters.py b/libs/labelbox/src/labelbox/schema/search_filters.py index 2badd5c47..d93eab5b7 100644 --- a/libs/labelbox/src/labelbox/schema/search_filters.py +++ b/libs/labelbox/src/labelbox/schema/search_filters.py @@ -2,7 +2,7 @@ from enum import Enum from typing import List, Literal, Union -from labelbox.pydantic_compat import BaseModel, validator +from pydantic import BaseModel, field_validator from labelbox.schema.labeling_service_status import LabelingServiceStatus from labelbox.utils import format_iso_datetime @@ -106,7 +106,6 @@ class WorkspaceFilter(BaseSearchFilter): class TagFilter(BaseSearchFilter): """ Filter for project tags - values are tag ids """ operation: Literal[OperationType.Tag] = OperationType.Tag @@ -123,7 +122,7 @@ class ProjectStageFilter(BaseSearchFilter): operator: IdOperator values: List[LabelingServiceStatus] - @validator('values', pre=True) + @field_validator('values') def validate_values(cls, values): disallowed_values = [LabelingServiceStatus.Missing] for value in values: diff --git a/libs/labelbox/tests/data/annotation_types/test_metrics.py b/libs/labelbox/tests/data/annotation_types/test_metrics.py index ebba1cb93..d2e488109 100644 --- a/libs/labelbox/tests/data/annotation_types/test_metrics.py +++ b/libs/labelbox/tests/data/annotation_types/test_metrics.py @@ -24,6 +24,7 @@ def test_legacy_scalar_metric(): 'extra': {}, }], 'extra': {}, + 'is_benchmark_reference': False } assert label.model_dump(exclude_none=True) == expected @@ -76,6 +77,7 @@ def test_custom_scalar_metric(feature_name, subclass_name, aggregation, value): 'extra': {} }], 'extra': {}, + 'is_benchmark_reference': False } assert label.model_dump(exclude_none=True) == expected @@ -123,6 +125,7 @@ def test_custom_confusison_matrix_metric(feature_name, subclass_name, 'extra': {} }], 'extra': {}, + 'is_benchmark_reference': False } assert label.model_dump(exclude_none=True) == expected From f811af2667c482a4649701b5994280861ad27173 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Tue, 27 Aug 2024 09:24:07 -0700 Subject: [PATCH 25/34] Convert labeling dashboard models to pydantic2 --- .../src/labelbox/schema/search_filters.py | 18 +++++++++--------- .../tests/unit/test_unit_search_filters.py | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/search_filters.py b/libs/labelbox/src/labelbox/schema/search_filters.py index d93eab5b7..888003be4 100644 --- a/libs/labelbox/src/labelbox/schema/search_filters.py +++ b/libs/labelbox/src/labelbox/schema/search_filters.py @@ -2,9 +2,10 @@ from enum import Enum from typing import List, Literal, Union -from pydantic import BaseModel, field_validator +from pydantic import BaseModel, Field, field_validator from labelbox.schema.labeling_service_status import LabelingServiceStatus from labelbox.utils import format_iso_datetime +from pydantic.config import ConfigDict class BaseSearchFilter(BaseModel): @@ -12,14 +13,10 @@ class BaseSearchFilter(BaseModel): Shared code for all search filters """ - class Config: - use_enum_values = True + model_config = ConfigDict(use_enum_values=True) def dict(self, *args, **kwargs): res = super().dict(*args, **kwargs) - if 'operation' in res: - res['type'] = res.pop('operation') - # go through all the keys and convert date to string for key in res: if isinstance(res[key], datetime.datetime): @@ -216,16 +213,19 @@ class TaskCompletedCountFilter(BaseSearchFilter): A task maps to a data row. Task completed should map to a data row in a labeling queue DONE """ operation: Literal[ - OperationType.TaskCompletedCount] = OperationType.TaskCompletedCount + OperationType.TaskCompletedCount] = Field(default=OperationType.TaskCompletedCount, serialization_alias='type') value: IntegerValue + + + class TaskRemainingCountFilter(BaseSearchFilter): """ Filter for remaining tasks count. Reverse of TaskCompletedCountFilter """ operation: Literal[ - OperationType.TaskRemainingCount] = OperationType.TaskRemainingCount + OperationType.TaskRemainingCount] = Field(OperationType.TaskRemainingCount, serialization_alias='type') value: IntegerValue @@ -253,5 +253,5 @@ def build_search_filter(filter: List[SearchFilter]): """ Converts a list of search filters to a graphql string """ - filters = [_dict_to_graphql_string(f.dict()) for f in filter] + filters = [_dict_to_graphql_string(f.model_dump(by_alias=True)) for f in filter] return "[" + ", ".join(filters) + "]" diff --git a/libs/labelbox/tests/unit/test_unit_search_filters.py b/libs/labelbox/tests/unit/test_unit_search_filters.py index 4ad2156f3..23100ae85 100644 --- a/libs/labelbox/tests/unit/test_unit_search_filters.py +++ b/libs/labelbox/tests/unit/test_unit_search_filters.py @@ -75,11 +75,11 @@ def test_date_range_filters(): def test_task_count_filters(): filters = [ - TaskCompletedCountFilter(value=IntegerValue( - operator=RangeOperatorWithSingleValue.GreaterThanOrEqual, value=1)), - TaskRemainingCountFilter(value=IntegerValue( - operator=RangeOperatorWithSingleValue.LessThanOrEqual, value=10)), + TaskCompletedCountFilter(value=IntegerValue(operator=RangeOperatorWithSingleValue.GreaterThanOrEqual, value=1)), + # TaskRemainingCountFilter(value=IntegerValue( + # operator=RangeOperatorWithSingleValue.LessThanOrEqual, value=10)), ] + # expected = '[{value: {operator: "GREATER_THAN_OR_EQUAL", value: 1}, type: "task_completed_count"}, {value: {operator: "LESS_THAN_OR_EQUAL", value: 10}, type: "task_remaining_count"}]' expected = '[{value: {operator: "GREATER_THAN_OR_EQUAL", value: 1}, type: "task_completed_count"}, {value: {operator: "LESS_THAN_OR_EQUAL", value: 10}, type: "task_remaining_count"}]' assert build_search_filter(filters) == expected From 65e27aaa1f2e3d2909a12ea1a0ca4e408065fd5a Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Tue, 27 Aug 2024 16:21:03 -0700 Subject: [PATCH 26/34] Fix search filters --- .../src/labelbox/schema/search_filters.py | 94 ++++++++++--------- .../tests/unit/test_unit_search_filters.py | 16 ++-- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/search_filters.py b/libs/labelbox/src/labelbox/schema/search_filters.py index 888003be4..93081305c 100644 --- a/libs/labelbox/src/labelbox/schema/search_filters.py +++ b/libs/labelbox/src/labelbox/schema/search_filters.py @@ -1,11 +1,13 @@ import datetime from enum import Enum -from typing import List, Literal, Union +from typing import List, Union +from pydantic import PlainSerializer, BaseModel, Field + +from typing_extensions import Annotated from pydantic import BaseModel, Field, field_validator from labelbox.schema.labeling_service_status import LabelingServiceStatus from labelbox.utils import format_iso_datetime -from pydantic.config import ConfigDict class BaseSearchFilter(BaseModel): @@ -13,18 +15,11 @@ class BaseSearchFilter(BaseModel): Shared code for all search filters """ - model_config = ConfigDict(use_enum_values=True) - - def dict(self, *args, **kwargs): - res = super().dict(*args, **kwargs) - # go through all the keys and convert date to string - for key in res: - if isinstance(res[key], datetime.datetime): - res[key] = format_iso_datetime(res[key]) - return res + class Config: + use_enum_values = True -class OperationType(Enum): +class OperationTypeEnum(Enum): """ Supported search entity types Each type corresponds to a different filter class @@ -40,6 +35,13 @@ class OperationType(Enum): TaskRemainingCount = 'task_remaining_count' +OperationType = Annotated[OperationTypeEnum, + PlainSerializer(lambda x: x.value, return_type=str)] + +IsoDatetimeType = Annotated[datetime.datetime, + PlainSerializer(format_iso_datetime)] + + class IdOperator(Enum): """ Supported operators for ids like org ids, workspace ids, etc @@ -75,7 +77,8 @@ class OrganizationFilter(BaseSearchFilter): """ Filter for organization to which projects belong """ - operation: Literal[OperationType.Organization] = OperationType.Organization + operation: OperationType = Field(default=OperationTypeEnum.Organization, + serialization_alias='type') operator: IdOperator values: List[str] @@ -84,9 +87,10 @@ class SharedWithOrganizationFilter(BaseSearchFilter): """ Find project shared with the organization (i.e. not having this organization as a tenantId) """ - operation: Literal[ - OperationType. - SharedWithOrganization] = OperationType.SharedWithOrganization + + operation: OperationType = Field( + default=OperationTypeEnum.SharedWithOrganization, + serialization_alias='type') operator: IdOperator values: List[str] @@ -95,7 +99,8 @@ class WorkspaceFilter(BaseSearchFilter): """ Filter for workspace """ - operation: Literal[OperationType.Workspace] = OperationType.Workspace + operation: OperationType = Field(default=OperationTypeEnum.Workspace, + serialization_alias='type') operator: IdOperator values: List[str] @@ -105,7 +110,8 @@ class TagFilter(BaseSearchFilter): Filter for project tags values are tag ids """ - operation: Literal[OperationType.Tag] = OperationType.Tag + operation: OperationType = Field(default=OperationTypeEnum.Tag, + serialization_alias='type') operator: IdOperator values: List[str] @@ -115,11 +121,12 @@ class ProjectStageFilter(BaseSearchFilter): Filter labelbox service / aka project stages Stages are: requested, in_progress, completed etc. as described by LabelingServiceStatus """ - operation: Literal[OperationType.Stage] = OperationType.Stage + operation: OperationType = Field(default=OperationTypeEnum.Stage, + serialization_alias='type') operator: IdOperator values: List[LabelingServiceStatus] - @field_validator('values') + @field_validator('values', mode='before') def validate_values(cls, values): disallowed_values = [LabelingServiceStatus.Missing] for value in values: @@ -143,7 +150,7 @@ class DateValue(BaseSearchFilter): while the same string in EST will get converted to '2024-01-01T05:00:00Z' """ operator: RangeDateTimeOperatorWithSingleValue - value: datetime.datetime + value: IsoDatetimeType class IntegerValue(BaseSearchFilter): @@ -155,9 +162,9 @@ class WorkforceStageUpdatedFilter(BaseSearchFilter): """ Filter for workforce stage updated date """ - operation: Literal[ - OperationType. - WorkforceStageUpdatedDate] = OperationType.WorkforceStageUpdatedDate + operation: OperationType = Field( + default=OperationTypeEnum.WorkforceStageUpdatedDate, + serialization_alias='type') value: DateValue @@ -165,9 +172,9 @@ class WorkforceRequestedDateFilter(BaseSearchFilter): """ Filter for workforce requested date """ - operation: Literal[ - OperationType. - WorforceRequestedDate] = OperationType.WorforceRequestedDate + operation: OperationType = Field( + default=OperationTypeEnum.WorforceRequestedDate, + serialization_alias='type') value: DateValue @@ -175,8 +182,8 @@ class DateRange(BaseSearchFilter): """ Date range for a search filter """ - min: datetime.datetime - max: datetime.datetime + min: IsoDatetimeType + max: IsoDatetimeType class DateRangeValue(BaseSearchFilter): @@ -191,9 +198,9 @@ class WorkforceRequestedDateRangeFilter(BaseSearchFilter): """ Filter for workforce requested date range """ - operation: Literal[ - OperationType. - WorforceRequestedDate] = OperationType.WorforceRequestedDate + operation: OperationType = Field( + default=OperationTypeEnum.WorforceRequestedDate, + serialization_alias='type') value: DateRangeValue @@ -201,9 +208,9 @@ class WorkforceStageUpdatedRangeFilter(BaseSearchFilter): """ Filter for workforce stage updated date range """ - operation: Literal[ - OperationType. - WorkforceStageUpdatedDate] = OperationType.WorkforceStageUpdatedDate + operation: OperationType = Field( + default=OperationTypeEnum.WorkforceStageUpdatedDate, + serialization_alias='type') value: DateRangeValue @@ -212,20 +219,19 @@ class TaskCompletedCountFilter(BaseSearchFilter): Filter for completed tasks count A task maps to a data row. Task completed should map to a data row in a labeling queue DONE """ - operation: Literal[ - OperationType.TaskCompletedCount] = Field(default=OperationType.TaskCompletedCount, serialization_alias='type') + operation: OperationType = Field( + default=OperationTypeEnum.TaskCompletedCount, + serialization_alias='type') value: IntegerValue - - - class TaskRemainingCountFilter(BaseSearchFilter): """ Filter for remaining tasks count. Reverse of TaskCompletedCountFilter """ - operation: Literal[ - OperationType.TaskRemainingCount] = Field(OperationType.TaskRemainingCount, serialization_alias='type') + operation: OperationType = Field( + default=OperationTypeEnum.TaskRemainingCount, + serialization_alias='type') value: IntegerValue @@ -253,5 +259,7 @@ def build_search_filter(filter: List[SearchFilter]): """ Converts a list of search filters to a graphql string """ - filters = [_dict_to_graphql_string(f.model_dump(by_alias=True)) for f in filter] + filters = [ + _dict_to_graphql_string(f.model_dump(by_alias=True)) for f in filter + ] return "[" + ", ".join(filters) + "]" diff --git a/libs/labelbox/tests/unit/test_unit_search_filters.py b/libs/labelbox/tests/unit/test_unit_search_filters.py index 23100ae85..eba8d4db8 100644 --- a/libs/labelbox/tests/unit/test_unit_search_filters.py +++ b/libs/labelbox/tests/unit/test_unit_search_filters.py @@ -20,7 +20,7 @@ def test_id_filters(): assert build_search_filter( filters - ) == '[{operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"], type: "organization_id"}, {operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"], type: "shared_with_organizations"}, {operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"], type: "workspace"}, {operator: "is", values: ["cls1vkrw401ab072vg2pq3t5d"], type: "tag"}, {operator: "is", values: ["REQUESTED"], type: "stage"}]' + ) == '[{type: "organization_id", operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"]}, {type: "shared_with_organizations", operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"]}, {type: "workspace", operator: "is", values: ["clphb4vd7000cd2wv1ktu5cwa"]}, {type: "tag", operator: "is", values: ["cls1vkrw401ab072vg2pq3t5d"]}, {type: "stage", operator: "is", values: ["REQUESTED"]}]' def test_stage_filter_with_invalid_values(): @@ -49,7 +49,7 @@ def test_date_filters(): expected_start = format_iso_datetime(local_time_start) expected_end = format_iso_datetime(local_time_end) - expected = '[{value: {operator: "GREATER_THAN_OR_EQUAL", value: "' + expected_start + '"}, type: "workforce_requested_at"}, {value: {operator: "LESS_THAN_OR_EQUAL", value: "' + expected_end + '"}, type: "workforce_stage_updated_at"}]' + expected = '[{type: "workforce_requested_at", value: {operator: "GREATER_THAN_OR_EQUAL", value: "' + expected_start + '"}}, {type: "workforce_stage_updated_at", value: {operator: "LESS_THAN_OR_EQUAL", value: "' + expected_end + '"}}]' assert build_search_filter(filters) == expected @@ -70,16 +70,16 @@ def test_date_range_filters(): ] assert build_search_filter( filters - ) == '[{value: {operator: "BETWEEN", value: {min: "2024-01-01T08:00:00Z", max: "2025-01-01T08:00:00Z"}}, type: "workforce_requested_at"}, {value: {operator: "BETWEEN", value: {min: "2024-01-01T08:00:00Z", max: "2025-01-01T08:00:00Z"}}, type: "workforce_stage_updated_at"}]' + ) == '[{type: "workforce_requested_at", value: {operator: "BETWEEN", value: {min: "2024-01-01T08:00:00Z", max: "2025-01-01T08:00:00Z"}}}, {type: "workforce_stage_updated_at", value: {operator: "BETWEEN", value: {min: "2024-01-01T08:00:00Z", max: "2025-01-01T08:00:00Z"}}}]' def test_task_count_filters(): filters = [ - TaskCompletedCountFilter(value=IntegerValue(operator=RangeOperatorWithSingleValue.GreaterThanOrEqual, value=1)), - # TaskRemainingCountFilter(value=IntegerValue( - # operator=RangeOperatorWithSingleValue.LessThanOrEqual, value=10)), + TaskCompletedCountFilter(value=IntegerValue( + operator=RangeOperatorWithSingleValue.GreaterThanOrEqual, value=1)), + TaskRemainingCountFilter(value=IntegerValue( + operator=RangeOperatorWithSingleValue.LessThanOrEqual, value=10)), ] - # expected = '[{value: {operator: "GREATER_THAN_OR_EQUAL", value: 1}, type: "task_completed_count"}, {value: {operator: "LESS_THAN_OR_EQUAL", value: 10}, type: "task_remaining_count"}]' - expected = '[{value: {operator: "GREATER_THAN_OR_EQUAL", value: 1}, type: "task_completed_count"}, {value: {operator: "LESS_THAN_OR_EQUAL", value: 10}, type: "task_remaining_count"}]' + expected = '[{type: "task_completed_count", value: {operator: "GREATER_THAN_OR_EQUAL", value: 1}}, {type: "task_remaining_count", value: {operator: "LESS_THAN_OR_EQUAL", value: 10}}]' assert build_search_filter(filters) == expected From be3846339ce0ad7f2930c2a749db88e3c11885ab Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Fri, 30 Aug 2024 13:50:10 -0700 Subject: [PATCH 27/34] Update pydantic types to Annotated --- .../data/annotation_types/metrics/scalar.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py index 04279892a..560d6dcef 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/metrics/scalar.py @@ -1,11 +1,13 @@ from typing import Dict, Optional, Union +from typing_extensions import Annotated from enum import Enum -from .base import ConfidenceValue, BaseMetric +from pydantic import field_validator +from pydantic.types import confloat -from pydantic import confloat, field_validator, model_serializer +from .base import ConfidenceValue, BaseMetric -ScalarMetricValue = confloat(ge=0, le=100_000_000) +ScalarMetricValue = Annotated[float, confloat(ge=0, le=100_000_000)] ScalarMetricConfidenceValue = Dict[ConfidenceValue, ScalarMetricValue] @@ -27,11 +29,12 @@ class ScalarMetric(BaseMetric): For backwards compatibility, metric_name is optional. The metric_name will be set to a default name in the editor if it is not set. This is not recommended and support for empty metric_name fields will be removed. - aggregation will be ignored wihtout providing a metric name. + aggregation will be ignored without providing a metric name. """ metric_name: Optional[str] = None value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] - aggregation: ScalarMetricAggregation = ScalarMetricAggregation.ARITHMETIC_MEAN + aggregation: Optional[ + ScalarMetricAggregation] = ScalarMetricAggregation.ARITHMETIC_MEAN @field_validator('metric_name') def validate_metric_name(cls, name: Union[str, None]): From e16989468bb01c95d0db6a858c89c696183f46a3 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:42:38 -0500 Subject: [PATCH 28/34] feedback --- .../annotation_types/data/conversation.py | 4 +- .../data/serialization/ndjson/base.py | 10 ++-- .../serialization/ndjson/classification.py | 10 ++-- .../data/serialization/ndjson/converter.py | 3 +- .../data/serialization/ndjson/label.py | 47 +++++++++---------- .../data/serialization/ndjson/metric.py | 6 +-- .../data/serialization/ndjson/objects.py | 36 +++++++------- .../data/serialization/ndjson/relationship.py | 4 +- .../ndjson/test_ndlabel_subclass_matching.py | 17 +++++++ 9 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 libs/labelbox/tests/data/serialization/ndjson/test_ndlabel_subclass_matching.py diff --git a/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py b/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py index 99078c48c..0a8a5a5a1 100644 --- a/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py +++ b/libs/labelbox/src/labelbox/data/annotation_types/data/conversation.py @@ -3,5 +3,5 @@ from .base_data import BaseData -class ConversationData(BaseData): - pass \ No newline at end of file +class ConversationData(BaseData, _NoCoercionMixin): + class_name: Literal["DicomData"] = "ConversationData" \ No newline at end of file diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py index 9d18f2ec5..602fa7628 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/base.py @@ -3,19 +3,21 @@ from labelbox.utils import _CamelCaseMixin, is_exactly_one_set from ...annotation_types.types import Cuid -from pydantic import field_validator, model_validator, model_serializer, ConfigDict, BaseModel, Field -from uuid import UUID, uuid4 +from pydantic import model_validator, ConfigDict, BaseModel, Field +from uuid import uuid4 +import threading subclass_registry = {} -class SubclassRegistryBase(BaseModel): +class _SubclassRegistryBase(BaseModel): model_config = ConfigDict(extra="allow") def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) if cls.__name__ != "NDAnnotation": - subclass_registry[cls.__name__] = cls + with threading.Lock(): + subclass_registry[cls.__name__] = cls class DataRow(_CamelCaseMixin): id: Optional[str] = None diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py index 299f49da7..e655e9f36 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/classification.py @@ -11,7 +11,7 @@ from ...annotation_types.data import TextData, VideoData, ImageData from pydantic import model_validator, Field, BaseModel, ConfigDict, model_serializer from pydantic.alias_generators import to_camel -from .base import SubclassRegistryBase +from .base import _SubclassRegistryBase class NDAnswer(ConfidenceMixin, CustomMetricsMixin): @@ -170,7 +170,7 @@ def from_common(cls, prompt_text: PromptText, name: str, # ====== End of subclasses -class NDText(NDAnnotation, NDTextSubclass, SubclassRegistryBase): +class NDText(NDAnnotation, NDTextSubclass, _SubclassRegistryBase): @classmethod def from_common(cls, @@ -194,7 +194,7 @@ def from_common(cls, ) -class NDChecklist(NDAnnotation, NDChecklistSubclass, VideoSupported, SubclassRegistryBase): +class NDChecklist(NDAnnotation, NDChecklistSubclass, VideoSupported, _SubclassRegistryBase): @model_serializer(mode="wrap") def serialize_model(self, handler): @@ -237,7 +237,7 @@ def from_common( confidence=confidence) -class NDRadio(NDAnnotation, NDRadioSubclass, VideoSupported, SubclassRegistryBase): +class NDRadio(NDAnnotation, NDRadioSubclass, VideoSupported, _SubclassRegistryBase): @classmethod def from_common( @@ -275,7 +275,7 @@ def serialize_model(self, handler): return res -class NDPromptText(NDAnnotation, NDPromptTextSubclass, SubclassRegistryBase): +class NDPromptText(NDAnnotation, NDPromptTextSubclass, _SubclassRegistryBase): @classmethod def from_common( diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py index 1046f82e9..88af6eff9 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/converter.py @@ -34,8 +34,7 @@ def deserialize(json_data: Iterable[Dict[str, Any]]) -> LabelGenerator: Returns: LabelGenerator containing the ndjson data. """ - data = copy.copy(json_data) - data = NDLabel(**{"annotations": data}) + data = NDLabel(**{"annotations": copy.copy(json_data)}) res = data.to_common() return res diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index 8c69b8667..7b92b18b8 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -2,9 +2,6 @@ from operator import itemgetter from typing import Dict, Generator, List, Tuple, Union from collections import defaultdict -from typing_extensions import Unpack -import warnings - from ...annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation from ...annotation_types.relationship import RelationshipAnnotation @@ -23,10 +20,9 @@ from .objects import NDObject, NDObjectType, NDSegments, NDDicomSegments, NDVideoMasks, NDDicomMasks from .relationship import NDRelationship from .base import DataRow -from pydantic import BaseModel, ConfigDict, model_serializer, ValidationError -from .base import subclass_registry, SubclassRegistryBase, NDAnnotation +from pydantic import BaseModel, ValidationError +from .base import subclass_registry, _SubclassRegistryBase from pydantic_core import PydanticUndefined -from pydantic.alias_generators import to_camel from contextlib import suppress AnnotationType = Union[NDObjectType, NDClassificationType, NDPromptClassificationType, @@ -36,48 +32,51 @@ class NDLabel(BaseModel): - annotations: List[SubclassRegistryBase] + annotations: List[_SubclassRegistryBase] def __init__(self, **kwargs): # NOTE: Deserialization of subclasses in pydantic is difficult, see here https://blog.devgenius.io/deserialize-child-classes-with-pydantic-that-gonna-work-784230e1cf83 # Below implements the subclass registry as mentioned in the article. The python dicts we pass in can be missing certain fields - # we essentially have to infer the type against all sub classes that have the SubclasssRegistryBase inheritance. + # we essentially have to infer the type against all sub classes that have the _SubclasssRegistryBase inheritance. # It works by checking if the keys of our annotations we are missing in matches any required subclass. # More keys are prioritized over less keys (closer match). This is used when importing json to our base models not a lot of customer workflows # depend on this method but this works for all our existing tests with the bonus of added validation. (no subclass found it throws an error) - # Previous strategies hacked but dont work for pydantic V2 - for index in range(len(kwargs["annotations"])): - annotation = kwargs["annotations"][index] + + for index, annotation in enumerate(kwargs["annotations"]): if isinstance(annotation, dict): item_annotation_keys = annotation.keys() key_subclass_combos = defaultdict(list) - for name, subclass in subclass_registry.items(): - subclass: BaseModel = subclass + for subclass in subclass_registry.values(): # Get all required keys from subclass annotation_keys = [] for k, field in subclass.model_fields.items(): - # must account for alias - if hasattr(field, "validation_alias") and field.validation_alias == "answers" and "answers" in item_annotation_keys: - annotation_keys.append("answers") - elif field.default == PydanticUndefined and k != "uuid": - annotation_keys.append(to_camel(k)) + if field.default == PydanticUndefined and k != "uuid": + if hasattr(field, "alias") and field.alias in item_annotation_keys: + annotation_keys.append(field.alias) + else: + annotation_keys.append(k) + key_subclass_combos[subclass].extend(annotation_keys) - - # Sort by subclass that has the most keys + + # Sort by subclass that has the most keys i.e. the one with the most keys that matches is most likely our subclass key_subclass_combos = dict(sorted(key_subclass_combos.items(), key = lambda x : len(x[1]), reverse=True)) - - # Choose the key that our dict we are passing in has all the keys to match + for subclass, key_subclass_combo in key_subclass_combos.items(): + # Choose the keys from our dict we supplied that matches the required keys of a subclass check_required_keys = all(key in list(item_annotation_keys) for key in key_subclass_combo) if check_required_keys: - # Keep trying subclasses until we find one that has valid values + # Keep trying subclasses until we find one that has valid values (does not throw an validation error) with suppress(ValidationError): annotation = subclass(**annotation) break - kwargs["annotations"][index] = annotation + if isinstance(annotation, dict): + raise ValueError(f"Could not find subclass for fields: {item_annotation_keys}") + + kwargs["annotations"][index] = annotation super().__init__(**kwargs) + class _Relationship(BaseModel): """This object holds information about the relationship""" ndjson: NDRelationship diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py index 16f426dc4..9fd90544c 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/metric.py @@ -9,7 +9,7 @@ ConfusionMatrixAggregation, ConfusionMatrixMetric, ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue) from pydantic import ConfigDict, model_serializer -from .base import SubclassRegistryBase +from .base import _SubclassRegistryBase class BaseNDMetric(NDJsonBase): @@ -27,7 +27,7 @@ def serialize_model(self, handler): return res -class NDConfusionMatrixMetric(BaseNDMetric, SubclassRegistryBase): +class NDConfusionMatrixMetric(BaseNDMetric, _SubclassRegistryBase): metric_value: Union[ConfusionMatrixMetricValue, ConfusionMatrixMetricConfidenceValue] metric_name: str @@ -54,7 +54,7 @@ def from_common( data_row=DataRow(id=data.uid, global_key=data.global_key)) -class NDScalarMetric(BaseNDMetric, SubclassRegistryBase): +class NDScalarMetric(BaseNDMetric, _SubclassRegistryBase): metric_value: Union[ScalarMetricValue, ScalarMetricConfidenceValue] metric_name: Optional[str] = None aggregation: Optional[ScalarMetricAggregation] = ScalarMetricAggregation.ARITHMETIC_MEAN diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py index 286cb2e24..2b32f1c2b 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/objects.py @@ -19,7 +19,7 @@ from ...annotation_types.annotation import ClassificationAnnotation, ObjectAnnotation from ...annotation_types.video import VideoMaskAnnotation, DICOMMaskAnnotation, MaskFrame, MaskInstance from .classification import NDClassification, NDSubclassification, NDSubclassificationType -from .base import DataRow, NDAnnotation, NDJsonBase, SubclassRegistryBase +from .base import DataRow, NDAnnotation, NDJsonBase, _SubclassRegistryBase from pydantic import BaseModel @@ -48,7 +48,7 @@ class Bbox(BaseModel): width: float -class NDPoint(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDPoint(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): point: _Point def to_common(self) -> Point: @@ -79,7 +79,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFramePoint(VideoSupported, SubclassRegistryBase): +class NDFramePoint(VideoSupported, _SubclassRegistryBase): point: _Point classifications: List[NDSubclassificationType] = [] @@ -109,7 +109,7 @@ def from_common( classifications=classifications) -class NDLine(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDLine(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): line: List[_Point] def to_common(self) -> Line: @@ -140,7 +140,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFrameLine(VideoSupported, SubclassRegistryBase): +class NDFrameLine(VideoSupported, _SubclassRegistryBase): line: List[_Point] classifications: List[NDSubclassificationType] = [] @@ -173,7 +173,7 @@ def from_common( classifications=classifications) -class NDDicomLine(NDFrameLine, SubclassRegistryBase): +class NDDicomLine(NDFrameLine, _SubclassRegistryBase): def to_common(self, name: str, feature_schema_id: Cuid, segment_index: int, group_key: str) -> DICOMObjectAnnotation: @@ -187,7 +187,7 @@ def to_common(self, name: str, feature_schema_id: Cuid, segment_index: int, group_key=group_key) -class NDPolygon(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDPolygon(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): polygon: List[_Point] def to_common(self) -> Polygon: @@ -218,7 +218,7 @@ def from_common( custom_metrics=custom_metrics) -class NDRectangle(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDRectangle(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): bbox: Bbox def to_common(self) -> Rectangle: @@ -254,7 +254,7 @@ def from_common( custom_metrics=custom_metrics) -class NDDocumentRectangle(NDRectangle, SubclassRegistryBase): +class NDDocumentRectangle(NDRectangle, _SubclassRegistryBase): page: int unit: str @@ -293,7 +293,7 @@ def from_common( custom_metrics=custom_metrics) -class NDFrameRectangle(VideoSupported, SubclassRegistryBase): +class NDFrameRectangle(VideoSupported, _SubclassRegistryBase): bbox: Bbox classifications: List[NDSubclassificationType] = [] @@ -398,7 +398,7 @@ def to_common(self, name: str, feature_schema_id: Cuid, uuid: str, ] -class NDSegments(NDBaseObject, SubclassRegistryBase): +class NDSegments(NDBaseObject, _SubclassRegistryBase): segments: List[NDSegment] def to_common(self, name: str, feature_schema_id: Cuid): @@ -425,7 +425,7 @@ def from_common(cls, segments: List[VideoObjectAnnotation], data: VideoData, uuid=extra.get('uuid')) -class NDDicomSegments(NDBaseObject, DicomSupported, SubclassRegistryBase): +class NDDicomSegments(NDBaseObject, DicomSupported, _SubclassRegistryBase): segments: List[NDDicomSegment] def to_common(self, name: str, feature_schema_id: Cuid): @@ -463,7 +463,7 @@ class _PNGMask(BaseModel): png: str -class NDMask(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDMask(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): mask: Union[_URIMask, _PNGMask] def to_common(self) -> Mask: @@ -517,7 +517,7 @@ class NDVideoMasksFramesInstances(BaseModel): instances: List[MaskInstance] -class NDVideoMasks(NDJsonBase, ConfidenceMixin, CustomMetricsNotSupportedMixin, SubclassRegistryBase): +class NDVideoMasks(NDJsonBase, ConfidenceMixin, CustomMetricsNotSupportedMixin, _SubclassRegistryBase): masks: NDVideoMasksFramesInstances def to_common(self) -> VideoMaskAnnotation: @@ -545,7 +545,7 @@ def from_common(cls, annotation, data): ) -class NDDicomMasks(NDVideoMasks, DicomSupported, SubclassRegistryBase): +class NDDicomMasks(NDVideoMasks, DicomSupported, _SubclassRegistryBase): def to_common(self) -> DICOMMaskAnnotation: return DICOMMaskAnnotation( @@ -569,7 +569,7 @@ class Location(BaseModel): end: int -class NDTextEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDTextEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): location: Location def to_common(self) -> TextEntity: @@ -601,7 +601,7 @@ def from_common( custom_metrics=custom_metrics) -class NDDocumentEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, SubclassRegistryBase): +class NDDocumentEntity(NDBaseObject, ConfidenceMixin, CustomMetricsMixin, _SubclassRegistryBase): name: str text_selections: List[DocumentTextSelection] @@ -633,7 +633,7 @@ def from_common( custom_metrics=custom_metrics) -class NDConversationEntity(NDTextEntity, SubclassRegistryBase): +class NDConversationEntity(NDTextEntity, _SubclassRegistryBase): message_id: str def to_common(self) -> ConversationEntity: diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py index e3e49ad5d..1cdb23b76 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/relationship.py @@ -5,7 +5,7 @@ from ...annotation_types.relationship import RelationshipAnnotation from ...annotation_types.relationship import Relationship from .objects import NDObjectType -from .base import DataRow, SubclassRegistryBase +from .base import DataRow, _SubclassRegistryBase SUPPORTED_ANNOTATIONS = NDObjectType @@ -16,7 +16,7 @@ class _Relationship(BaseModel): type: str -class NDRelationship(NDAnnotation, SubclassRegistryBase): +class NDRelationship(NDAnnotation, _SubclassRegistryBase): relationship: _Relationship @staticmethod diff --git a/libs/labelbox/tests/data/serialization/ndjson/test_ndlabel_subclass_matching.py b/libs/labelbox/tests/data/serialization/ndjson/test_ndlabel_subclass_matching.py new file mode 100644 index 000000000..1f51c307a --- /dev/null +++ b/libs/labelbox/tests/data/serialization/ndjson/test_ndlabel_subclass_matching.py @@ -0,0 +1,17 @@ +import json +from labelbox.data.serialization.ndjson.label import NDLabel +from labelbox.data.serialization.ndjson.objects import NDDocumentRectangle +import pytest + + +def test_bad_annotation_input(): + data = [{ + "test": 3 + }] + with pytest.raises(ValueError): + NDLabel(**{"annotations": data}) + +def test_correct_annotation_input(): + with open('tests/data/assets/ndjson/pdf_import_name_only.json', 'r') as f: + data = json.load(f) + assert isinstance(NDLabel(**{"annotations": [data[0]]}).annotations[0], NDDocumentRectangle) From 38d81274d4eb8ba41055012fb0f85212c1b55c03 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Sun, 1 Sep 2024 22:19:26 -0500 Subject: [PATCH 29/34] added validation_alias --- libs/labelbox/src/labelbox/data/serialization/ndjson/label.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py index 7b92b18b8..f49b4dd44 100644 --- a/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py +++ b/libs/labelbox/src/labelbox/data/serialization/ndjson/label.py @@ -54,6 +54,8 @@ def __init__(self, **kwargs): if field.default == PydanticUndefined and k != "uuid": if hasattr(field, "alias") and field.alias in item_annotation_keys: annotation_keys.append(field.alias) + elif hasattr(field, "validation_alias") and field.validation_alias in item_annotation_keys: + annotation_keys.append(field.validation_alias) else: annotation_keys.append(k) From 6e1ac84a5fa85c547dcaee5d795996ab5bc13916 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Tue, 3 Sep 2024 11:01:20 -0700 Subject: [PATCH 30/34] Fix tests post-merge --- .../src/labelbox/schema/search_filters.py | 42 ++++++++++--------- .../integration/test_labeling_dashboard.py | 3 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/search_filters.py b/libs/labelbox/src/labelbox/schema/search_filters.py index 93081305c..74ad6cb62 100644 --- a/libs/labelbox/src/labelbox/schema/search_filters.py +++ b/libs/labelbox/src/labelbox/schema/search_filters.py @@ -19,7 +19,7 @@ class Config: use_enum_values = True -class OperationTypeEnum(Enum): +class OperationType(Enum): """ Supported search entity types Each type corresponds to a different filter class @@ -35,8 +35,14 @@ class OperationTypeEnum(Enum): TaskRemainingCount = 'task_remaining_count' -OperationType = Annotated[OperationTypeEnum, - PlainSerializer(lambda x: x.value, return_type=str)] +def convert_enum_to_str(enum_or_str: Union[Enum, str]) -> str: + if isinstance(enum_or_str, Enum): + return enum_or_str.value + return enum_or_str + + +OperationType = Annotated[OperationType, + PlainSerializer(convert_enum_to_str, return_type=str)] IsoDatetimeType = Annotated[datetime.datetime, PlainSerializer(format_iso_datetime)] @@ -77,7 +83,7 @@ class OrganizationFilter(BaseSearchFilter): """ Filter for organization to which projects belong """ - operation: OperationType = Field(default=OperationTypeEnum.Organization, + operation: OperationType = Field(default=OperationType.Organization, serialization_alias='type') operator: IdOperator values: List[str] @@ -89,7 +95,7 @@ class SharedWithOrganizationFilter(BaseSearchFilter): """ operation: OperationType = Field( - default=OperationTypeEnum.SharedWithOrganization, + default=OperationType.SharedWithOrganization, serialization_alias='type') operator: IdOperator values: List[str] @@ -99,7 +105,7 @@ class WorkspaceFilter(BaseSearchFilter): """ Filter for workspace """ - operation: OperationType = Field(default=OperationTypeEnum.Workspace, + operation: OperationType = Field(default=OperationType.Workspace, serialization_alias='type') operator: IdOperator values: List[str] @@ -110,7 +116,7 @@ class TagFilter(BaseSearchFilter): Filter for project tags values are tag ids """ - operation: OperationType = Field(default=OperationTypeEnum.Tag, + operation: OperationType = Field(default=OperationType.Tag, serialization_alias='type') operator: IdOperator values: List[str] @@ -121,7 +127,7 @@ class ProjectStageFilter(BaseSearchFilter): Filter labelbox service / aka project stages Stages are: requested, in_progress, completed etc. as described by LabelingServiceStatus """ - operation: OperationType = Field(default=OperationTypeEnum.Stage, + operation: OperationType = Field(default=OperationType.Stage, serialization_alias='type') operator: IdOperator values: List[LabelingServiceStatus] @@ -163,7 +169,7 @@ class WorkforceStageUpdatedFilter(BaseSearchFilter): Filter for workforce stage updated date """ operation: OperationType = Field( - default=OperationTypeEnum.WorkforceStageUpdatedDate, + default=OperationType.WorkforceStageUpdatedDate, serialization_alias='type') value: DateValue @@ -173,8 +179,7 @@ class WorkforceRequestedDateFilter(BaseSearchFilter): Filter for workforce requested date """ operation: OperationType = Field( - default=OperationTypeEnum.WorforceRequestedDate, - serialization_alias='type') + default=OperationType.WorforceRequestedDate, serialization_alias='type') value: DateValue @@ -199,8 +204,7 @@ class WorkforceRequestedDateRangeFilter(BaseSearchFilter): Filter for workforce requested date range """ operation: OperationType = Field( - default=OperationTypeEnum.WorforceRequestedDate, - serialization_alias='type') + default=OperationType.WorforceRequestedDate, serialization_alias='type') value: DateRangeValue @@ -209,7 +213,7 @@ class WorkforceStageUpdatedRangeFilter(BaseSearchFilter): Filter for workforce stage updated date range """ operation: OperationType = Field( - default=OperationTypeEnum.WorkforceStageUpdatedDate, + default=OperationType.WorkforceStageUpdatedDate, serialization_alias='type') value: DateRangeValue @@ -219,9 +223,8 @@ class TaskCompletedCountFilter(BaseSearchFilter): Filter for completed tasks count A task maps to a data row. Task completed should map to a data row in a labeling queue DONE """ - operation: OperationType = Field( - default=OperationTypeEnum.TaskCompletedCount, - serialization_alias='type') + operation: OperationType = Field(default=OperationType.TaskCompletedCount, + serialization_alias='type') value: IntegerValue @@ -229,9 +232,8 @@ class TaskRemainingCountFilter(BaseSearchFilter): """ Filter for remaining tasks count. Reverse of TaskCompletedCountFilter """ - operation: OperationType = Field( - default=OperationTypeEnum.TaskRemainingCount, - serialization_alias='type') + operation: OperationType = Field(default=OperationType.TaskRemainingCount, + serialization_alias='type') value: IntegerValue diff --git a/libs/labelbox/tests/integration/test_labeling_dashboard.py b/libs/labelbox/tests/integration/test_labeling_dashboard.py index c2b0fda43..96d6af57f 100644 --- a/libs/labelbox/tests/integration/test_labeling_dashboard.py +++ b/libs/labelbox/tests/integration/test_labeling_dashboard.py @@ -20,8 +20,7 @@ def test_request_labeling_service_dashboard_filters(requested_labeling_service): project, _ = requested_labeling_service organization = project.client.get_organization() - org_filter = OrganizationFilter(operation=OperationType.Organization, - operator=IdOperator.Is, + org_filter = OrganizationFilter(operator=IdOperator.Is, values=[organization.uid]) try: From 5eeb681fcbc4ef8966b9c686b99c46b894a53421 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Tue, 3 Sep 2024 11:43:32 -0700 Subject: [PATCH 31/34] Address embedding test failures --- libs/labelbox/tests/conftest.py | 13 ++++--------- libs/labelbox/tests/integration/test_embedding.py | 10 +++------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/libs/labelbox/tests/conftest.py b/libs/labelbox/tests/conftest.py index a14accf87..6bc34cfc6 100644 --- a/libs/labelbox/tests/conftest.py +++ b/libs/labelbox/tests/conftest.py @@ -1074,20 +1074,15 @@ def configured_project_with_complex_ontology(client, initial_dataset, rand_gen, project.delete() -@pytest.fixture(scope="session") +@pytest.fixture def embedding(client: Client, environ): uuid_str = uuid.uuid4().hex + time.sleep(randint(1, 5)) embedding = client.create_embedding(f"sdk-int-{uuid_str}", 8) yield embedding - # Remove all embeddings on staging - if environ == Environ.STAGING: - embeddings = client.get_embeddings() - for embedding in embeddings: - with suppress(LabelboxError): - embedding.delete() - else: - embedding.delete() + + embedding.delete() @pytest.fixture diff --git a/libs/labelbox/tests/integration/test_embedding.py b/libs/labelbox/tests/integration/test_embedding.py index 5d0c51f56..541b6d980 100644 --- a/libs/labelbox/tests/integration/test_embedding.py +++ b/libs/labelbox/tests/integration/test_embedding.py @@ -15,22 +15,18 @@ def test_get_embedding_by_id(client: Client, embedding: Embedding): e = client.get_embedding_by_id(embedding.id) assert e.id == embedding.id - -def test_get_embedding_by_name(client: Client, embedding: Embedding): e = client.get_embedding_by_name(embedding.name) assert e.name == embedding.name + embeddings = client.get_embeddings() + assert len(embeddings) > 0 + def test_get_embedding_by_name_not_found(client: Client): with pytest.raises(labelbox.exceptions.ResourceNotFoundError): client.get_embedding_by_name("does-not-exist") -def test_get_embeddings(client: Client, embedding: Embedding): - embeddings = client.get_embeddings() - assert len(embeddings) > 0 - - @pytest.mark.parametrize('data_rows', [10], indirect=True) def test_import_vectors_from_file(data_rows: List[DataRow], embedding: Embedding): From 8c406c85f050222d03ecee50470808e237169526 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Tue, 3 Sep 2024 14:53:18 -0700 Subject: [PATCH 32/34] Refactour test_user_management to fix test failures --- libs/labelbox/tests/conftest.py | 8 +- .../tests/integration/test_user_management.py | 82 +++++++++++++++---- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/libs/labelbox/tests/conftest.py b/libs/labelbox/tests/conftest.py index 6bc34cfc6..4251ac698 100644 --- a/libs/labelbox/tests/conftest.py +++ b/libs/labelbox/tests/conftest.py @@ -594,14 +594,8 @@ def sample_bulk_conversation() -> list: def organization(client): # Must have at least one seat open in your org to run these tests org = client.get_organization() - # Clean up before and after incase this wasn't run for some reason. - for invite in get_invites(client): - if "@labelbox.com" in invite.email: - cancel_invite(client, invite.uid) + yield org - for invite in get_invites(client): - if "@labelbox.com" in invite.email: - cancel_invite(client, invite.uid) @pytest.fixture diff --git a/libs/labelbox/tests/integration/test_user_management.py b/libs/labelbox/tests/integration/test_user_management.py index 2061e669e..ca4328f51 100644 --- a/libs/labelbox/tests/integration/test_user_management.py +++ b/libs/labelbox/tests/integration/test_user_management.py @@ -5,9 +5,13 @@ faker = Faker() -def test_org_invite(client, organization, environ, queries): + +@pytest.fixture +def org_invite(client, organization, environ, queries): role = client.get_roles()['LABELER'] - dummy_email = "none+{}@labelbox.com".format("".join(faker.random_letters(26))) + + dummy_email = "none+{}@labelbox.com".format("".join( + faker.random_letters(26))) invite_limit = organization.invite_limit() if environ.value == "prod": @@ -18,6 +22,45 @@ def test_org_invite(client, organization, environ, queries): invite = organization.invite_user(dummy_email, role) + yield invite, invite_limit + + queries.cancel_invite(client, invite.uid) + + +@pytest.fixture +def project_role_1(client, project_pack): + project_1, _ = project_pack + roles = client.get_roles() + return ProjectRole(project=project_1, role=roles['LABELER']) + + +@pytest.fixture +def project_role_2(client, project_pack): + _, project_2 = project_pack + roles = client.get_roles() + return ProjectRole(project=project_2, role=roles['REVIEWER']) + + +@pytest.fixture +def create_project_invite(client, organization, project_pack, queries, + project_role_1, project_role_2): + roles = client.get_roles() + dummy_email = "none+{}@labelbox.com".format("".join( + faker.random_letters(26))) + invite = organization.invite_user( + dummy_email, + roles['NONE'], + project_roles=[project_role_1, project_role_2]) + + yield invite + + queries.cancel_invite(client, invite.uid) + + +def test_org_invite(client, organization, environ, queries, org_invite): + invite, invite_limit = org_invite + role = client.get_roles()['LABELER'] + if environ.value == "prod": invite_limit_after = organization.invite_limit() @@ -28,30 +71,36 @@ def test_org_invite(client, organization, environ, queries): outstanding_invites = queries.get_invites(client) in_list = False - for invite in outstanding_invites: - if invite.uid == invite.uid: + for outstanding_invite in outstanding_invites: + if outstanding_invite.uid == invite.uid: in_list = True - org_role = invite.organization_role_name.lower() + org_role = outstanding_invite.organization_role_name.lower() assert org_role == role.name.lower( ), "Role should be labeler. Found {org_role} " assert in_list, "Invite not found" + + +def test_cancel_invite( + client, + organization, + queries, +): + role = client.get_roles()['LABELER'] + dummy_email = "none+{}@labelbox.com".format("".join( + faker.random_letters(26))) + invite = organization.invite_user(dummy_email, role) queries.cancel_invite(client, invite.uid) - assert invite_limit.remaining - organization.invite_limit().remaining == 0 + outstanding_invites = [i.uid for i in queries.get_invites(client)] + assert invite.uid not in outstanding_invites -def test_project_invite(client, organization, project_pack, queries): - project_1, project_2 = project_pack +def test_project_invite(client, organization, project_pack, queries, + create_project_invite, project_role_1, project_role_2): + create_project_invite + project_1, _ = project_pack roles = client.get_roles() - dummy_email = "none+{}@labelbox.com".format("".join(faker.random_letters(26))) - project_role_1 = ProjectRole(project=project_1, role=roles['LABELER']) - project_role_2 = ProjectRole(project=project_2, role=roles['REVIEWER']) - invite = organization.invite_user( - dummy_email, - roles['NONE'], - project_roles=[project_role_1, project_role_2]) project_invite = next(queries.get_project_invites(client, project_1.uid)) - assert set([(proj_invite.project.uid, proj_invite.role.uid) for proj_invite in project_invite.project_roles ]) == set([(proj_role.project.uid, proj_role.role.uid) @@ -74,7 +123,6 @@ def test_project_invite(client, organization, project_pack, queries): assert project_member.access_from == 'ORGANIZATION' assert project_member.role().name.upper() == roles['ADMIN'].name.upper() - queries.cancel_invite(client, invite.uid) @pytest.mark.skip( From 9a37f5f0b2ea6fefa23f0b4b090f0c788194dcdf Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Wed, 4 Sep 2024 11:04:17 -0700 Subject: [PATCH 33/34] Remove flaky test_filtering test --- libs/labelbox/tests/integration/test_filtering.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/labelbox/tests/integration/test_filtering.py b/libs/labelbox/tests/integration/test_filtering.py index fc149d3d4..e751213cc 100644 --- a/libs/labelbox/tests/integration/test_filtering.py +++ b/libs/labelbox/tests/integration/test_filtering.py @@ -46,9 +46,6 @@ def get(where=None): assert p_a.uid in lt_b and p_b.uid not in lt_b and p_c.uid not in lt_b ge_b = get(Project.name >= p_b_name) assert {p_b.uid, p_c.uid}.issubset(ge_b) and p_a.uid not in ge_b - le_b = get(Project.name <= p_b_name) - assert {p_a.uid, p_b.uid}.issubset(le_b) and p_c.uid not in le_b - def test_unsupported_where(client): with pytest.raises(InvalidQueryError): From 9547311ab88bb4e29e6fbc677895d886281dd988 Mon Sep 17 00:00:00 2001 From: Val Brodsky Date: Thu, 5 Sep 2024 10:58:04 -0700 Subject: [PATCH 34/34] Trigger tests