Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/superannotate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from superannotate.lib.app.input_converters.conversion import convert_json_version
from superannotate.lib.app.input_converters.conversion import convert_project_type
from superannotate.lib.app.input_converters.conversion import export_annotation

from superannotate.lib.app.interface.sdk_interface import add_annotation_bbox_to_image
from superannotate.lib.app.interface.sdk_interface import (
add_annotation_comment_to_image,
Expand Down
2 changes: 1 addition & 1 deletion src/superannotate/lib/app/analytics/aggregators.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import copy
import json
import logging
from dataclasses import dataclass
from pathlib import Path
from typing import List
from typing import Optional
from typing import Union

import lib.core as constances
import pandas as pd
from dataclasses import dataclass
from lib.app.exceptions import AppException
from lib.core import ATTACHED_VIDEO_ANNOTATION_POSTFIX
from lib.core import PIXEL_ANNOTATION_POSTFIX
Expand Down
4 changes: 2 additions & 2 deletions src/superannotate/lib/app/annotation_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _postprocess_annotation_json(annotation_json, path):


def add_annotation_comment_to_json(
annotation_json, comment_text, comment_coords, comment_author, resolved=False
annotation_json, comment_text, comment_coords, comment_author, resolved=False, image_name=""
):
"""Add a comment to SuperAnnotate format annotation JSON

Expand All @@ -54,7 +54,7 @@ def add_annotation_comment_to_json(
if len(comment_coords) != 2:
raise AppException("Comment should have two values")

annotation_json, path = _preprocess_annotation_json(annotation_json)
annotation_json, path = _preprocess_annotation_json(annotation_json, image_name=image_name)

annotation = {
"type": "comment",
Expand Down
1 change: 0 additions & 1 deletion src/superannotate/lib/app/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import os
import sys
import time
from pathlib import Path

import numpy as np
from PIL import Image
Expand Down
1 change: 0 additions & 1 deletion src/superannotate/lib/app/input_converters/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from .import_to_sa_conversions import import_to_sa
from .sa_conversion import degrade_json
from .sa_conversion import sa_convert_project_type
from .sa_conversion import split_coco
from .sa_conversion import upgrade_json

ALLOWED_TASK_TYPES = [
Expand Down
51 changes: 0 additions & 51 deletions src/superannotate/lib/app/input_converters/sa_conversion.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
"""
"""
import json
import logging
import shutil
from pathlib import Path

import cv2
import numpy as np
Expand Down Expand Up @@ -192,54 +189,6 @@ def sa_convert_project_type(input_dir, output_dir):
copy_file(input_dir.joinpath(img_name), output_dir.joinpath(img_name))


def split_coco(coco_json_path, image_dir, output_dir, dataset_list_name, ratio_list):
coco_json = json.load(open(coco_json_path))

groups = {}
for dataset_name in dataset_list_name:
groups[dataset_name] = {
"info": coco_json["info"],
"licenses": coco_json["licenses"],
"images": [],
"annotations": [],
"categories": coco_json["categories"],
}

images = coco_json["images"]
np.random.shuffle(images)
num_of_images = len(images)
points = []
total = 0
for ratio in ratio_list:
total += ratio
point = total / 100 * num_of_images
points.append(int(point))

image_id_to_group_map = {}
group_id = 0
dataset_name = dataset_list_name[group_id]
(output_dir / dataset_name).mkdir(parents=True)
for i, image in enumerate(images):
if i in points:
group_id += 1
dataset_name = dataset_list_name[group_id]
(output_dir / dataset_name).mkdir()

image_name = Path(image["file_name"]).name
copy_file(image_dir / image_name, output_dir / dataset_name / image_name)

image_id_to_group_map[image["id"]] = group_id
groups[dataset_name]["images"].append(image)

for annotation in coco_json["annotations"]:
dataset_name = dataset_list_name[image_id_to_group_map[annotation["image_id"]]]
groups[dataset_name]["annotations"].append(annotation)

for file_name, value in groups.items():
with open(output_dir / (file_name + ".json"), "w") as fw:
json.dump(value, fw, indent=2)


def upgrade_json(input_dir, output_dir):
files_list = list(input_dir.glob("*.json"))
ptype = "Vector"
Expand Down
11 changes: 5 additions & 6 deletions src/superannotate/lib/app/interface/sdk_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import logging
import os
import tempfile
import time
from pathlib import Path
from typing import Iterable
from typing import List
Expand Down Expand Up @@ -40,7 +39,6 @@
from lib.core.types import MLModel
from lib.core.types import Project
from lib.infrastructure.controller import Controller
from plotly.subplots import make_subplots
from pydantic import EmailStr
from pydantic import parse_obj_as
from pydantic import StrictBool
Expand Down Expand Up @@ -2479,7 +2477,8 @@ def add_annotation_bbox_to_image(
error,
image_name,
)
upload_image_annotations(project, image_name, annotations, verbose=False)

controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)


@Trackable
Expand Down Expand Up @@ -2513,7 +2512,7 @@ def add_annotation_point_to_image(
annotations = add_annotation_point_to_json(
annotations, point, annotation_class_name, annotation_class_attributes, error
)
upload_image_annotations(project, image_name, annotations, verbose=False)
controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)


@Trackable
Expand Down Expand Up @@ -2542,9 +2541,9 @@ def add_annotation_comment_to_image(
"""
annotations = get_image_annotations(project, image_name)["annotation_json"]
annotations = add_annotation_comment_to_json(
annotations, comment_text, comment_coords, comment_author, resolved=resolved
annotations, comment_text, comment_coords, comment_author, resolved=resolved, image_name=image_name
)
upload_image_annotations(project, image_name, annotations, verbose=False)
controller.upload_image_annotations(*extract_project_folder(project), image_name, annotations)


@validate_arguments
Expand Down
3 changes: 2 additions & 1 deletion src/superannotate/lib/core/entities/project_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def from_dict(**kwargs):
return ImageEntity(**kwargs)

def to_dict(self):
return {
data = {
"id": self.uuid,
"team_id": self.team_id,
"name": self.name,
Expand All @@ -310,6 +310,7 @@ def to_dict(self):
"prediction_status": self.prediction_status,
"meta": self.meta.to_dict(),
}
return {k: v for k, v in data.items() if v is not None}


class S3FileEntity(BaseEntity):
Expand Down
6 changes: 3 additions & 3 deletions src/superannotate/lib/core/entities/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from pydantic import EmailStr
from pydantic import Extra
from pydantic import Field
from pydantic import StrictStr
from pydantic import StrictInt
from pydantic import StrictBool
from pydantic import StrictInt
from pydantic import StrictStr
from pydantic import StrRegexError
from pydantic import ValidationError
from pydantic import validator
Expand Down Expand Up @@ -199,7 +199,7 @@ class StringA(BaseModel):


class PointLabels(BaseModel):
__root__: Dict[constr(regex=r"^[0-9]+$"), StrictStr]
__root__: Dict[constr(regex=r"^[0-9]+$"), StrictStr] # noqa F722

@classmethod
def __get_validators__(cls):
Expand Down
2 changes: 1 addition & 1 deletion src/superannotate/lib/core/entities/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from lib.core.entities.utils import BaseVectorInstance
from lib.core.entities.utils import BboxPoints
from lib.core.entities.utils import Comment
from lib.core.entities.utils import INVALID_DICT_MESSAGE
from lib.core.entities.utils import Metadata
from lib.core.entities.utils import NotEmptyStr
from lib.core.entities.utils import Tag
from lib.core.entities.utils import VectorAnnotationTypeEnum
from lib.core.entities.utils import INVALID_DICT_MESSAGE
from pydantic import conlist
from pydantic import Field
from pydantic import StrictInt
Expand Down
6 changes: 3 additions & 3 deletions src/superannotate/lib/core/entities/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
from pydantic import BaseModel
from pydantic import constr
from pydantic import Field
from pydantic import StrictStr
from pydantic import StrictInt
from pydantic import StrictBool
from pydantic import StrictInt
from pydantic import StrictStr


class VideoType(str, Enum):
Expand Down Expand Up @@ -47,7 +47,7 @@ class BaseVideoInstance(BaseInstance):


class BboxInstance(BaseVideoInstance):
point_labels: Optional[Dict[constr(regex=r"^[0-9]+$"), NotEmptyStr]] = Field(
point_labels: Optional[Dict[constr(regex=r"^[0-9]+$"), NotEmptyStr]] = Field( # noqa F722
None, alias="pointLabels"
)
timeline: Dict[float, BboxTimeStamp]
Expand Down
3 changes: 1 addition & 2 deletions src/superannotate/lib/core/entities/video_export.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from enum import Enum
from typing import Dict
from typing import List
from typing import Optional
from typing import Union
Expand All @@ -8,10 +7,10 @@
from lib.core.entities.utils import BaseInstance
from lib.core.entities.utils import BaseModel
from lib.core.entities.utils import BboxPoints
from lib.core.entities.utils import INVALID_DICT_MESSAGE
from lib.core.entities.utils import MetadataBase
from lib.core.entities.utils import NotEmptyStr
from lib.core.entities.utils import PointLabels
from lib.core.entities.utils import INVALID_DICT_MESSAGE
from lib.core.entities.utils import Tag
from pydantic import conlist
from pydantic import Field
Expand Down
5 changes: 5 additions & 0 deletions src/superannotate/lib/core/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections import defaultdict
from typing import List

import lib.core as constances
from lib.core.entities import TeamEntity
from lib.core.reporter import Reporter

Expand Down Expand Up @@ -277,6 +278,10 @@ def handle_last_action(annotations: dict, team: TeamEntity):
}


def handle_annotation_status(annotations: dict):
annotations["metadata"]["status"] = constances.AnnotationStatus.IN_PROGRESS.value


class SetEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
Expand Down
21 changes: 15 additions & 6 deletions src/superannotate/lib/core/usecases/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
from lib.core.entities import TeamEntity
from lib.core.helpers import convert_to_video_editor_json
from lib.core.helpers import fill_annotation_ids
from lib.core.helpers import fill_document_tags
from lib.core.helpers import handle_last_action
from lib.core.helpers import map_annotation_classes_name
from lib.core.reporter import Reporter
from lib.core.repositories import BaseManageableRepository
from lib.core.service_types import UploadAnnotationAuthData
from lib.core.serviceproviders import SuerannotateServiceProvider
from lib.core.usecases.base import BaseReportableUseCae
Expand All @@ -42,6 +42,7 @@ def __init__(
project: ProjectEntity,
folder: FolderEntity,
team: TeamEntity,
images: BaseManageableRepository,
annotation_classes: List[AnnotationClassEntity],
annotation_paths: List[str],
backend_service_provider: SuerannotateServiceProvider,
Expand All @@ -55,6 +56,7 @@ def __init__(
self._project = project
self._folder = folder
self._team = team
self._images = images
self._backend_service = backend_service_provider
self._annotation_classes = annotation_classes
self._annotation_paths = annotation_paths
Expand Down Expand Up @@ -127,7 +129,8 @@ def annotations_to_upload(self):
)
if missing_annotations:
logger.warning(
f"Couldn't find {len(missing_annotations)}/{len(annotations_to_upload + missing_annotations)} items on the platform that match the annotations you want to upload."
f"Couldn't find {len(missing_annotations)}/{len(annotations_to_upload + missing_annotations)} "
"items on the platform that match the annotations you want to upload."
)
self._missing_annotations = missing_annotations
self._annotations_to_upload = annotations_to_upload
Expand Down Expand Up @@ -162,7 +165,8 @@ def _upload_annotation(
project=self._project,
folder=self._folder,
team=self._team,
image=ImageEntity(uuid=image_id, name=image_name),
image=ImageEntity(uuid=image_id, name=image_name, team_id=self._project.team_id, project_id=self._project.uuid),
images=self._images,
annotation_classes=self._annotation_classes,
backend_service_provider=self._backend_service,
reporter=self.reporter,
Expand Down Expand Up @@ -203,7 +207,8 @@ def _log_report(self):
if key == "missing_classes":
template = "Could not find annotation classes matching existing classes on the platform: [{}]"
elif key == "missing_attribute_groups":
template = "Could not find attribute groups matching existing attribute groups on the platform: [{}]"
template = "Could not find attribute groups matching existing attribute groups" \
" on the platform: [{}]"
elif key == "missing_attributes":
template = "Could not find attributes matching existing attributes on the platform: [{}]"
logger.warning(template.format("', '".join(values)))
Expand All @@ -224,8 +229,8 @@ def execute(self):
)
for step in iterations_range:
annotations_to_upload = self.annotations_to_upload[
step : step + self.AUTH_DATA_CHUNK_SIZE
] # noqa: E203
step : step + self.AUTH_DATA_CHUNK_SIZE # noqa: E203
]
upload_data = self.get_annotation_upload_data(
[int(image.id) for image in annotations_to_upload]
)
Expand Down Expand Up @@ -278,6 +283,7 @@ def __init__(
project: ProjectEntity,
folder: FolderEntity,
image: ImageEntity,
images: BaseManageableRepository,
team: TeamEntity,
annotation_classes: List[AnnotationClassEntity],
backend_service_provider: SuerannotateServiceProvider,
Expand All @@ -297,6 +303,7 @@ def __init__(
self._project = project
self._folder = folder
self._image = image
self._images = images
self._team = team
self._backend_service = backend_service_provider
self._annotation_classes = annotation_classes
Expand Down Expand Up @@ -454,6 +461,8 @@ def execute(self):
],
Body=self._mask,
)
self._image.annotation_status_code = constances.AnnotationStatus.IN_PROGRESS.value
self._images.update(self._image)
if self._verbose:
logger.info(
"Uploading annotations for image %s in project %s.",
Expand Down
1 change: 0 additions & 1 deletion src/superannotate/lib/core/usecases/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from lib.core.entities import MLModelEntity
from lib.core.entities import ProjectEntity
from lib.core.enums import ExportStatus
from lib.core.enums import ProjectType
from lib.core.exceptions import AppException
from lib.core.exceptions import AppValidationException
from lib.core.repositories import BaseManageableRepository
Expand Down
1 change: 0 additions & 1 deletion src/superannotate/lib/core/usecases/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from lib.core.entities import FolderEntity
from lib.core.entities import ProjectEntity
from lib.core.entities import ProjectSettingEntity
from lib.core.entities import TeamEntity
from lib.core.entities import WorkflowEntity
from lib.core.exceptions import AppException
from lib.core.exceptions import AppValidationException
Expand Down
Loading