Skip to content

Commit cee5c91

Browse files
Vaghinak BasentsyanVaghinak Basentsyan
authored andcommitted
Fixed issues 311, 330, 331
1 parent b3ee6de commit cee5c91

File tree

5 files changed

+58
-16
lines changed

5 files changed

+58
-16
lines changed

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
minversion = 3.0
33
log_cli=true
44
python_files = test_*.py
5-
addopts = -n 32 --dist=loadscope
5+
addopts = -n32 --dist=loadscope

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,8 @@ def copy_image(
607607
is_pinned=1,
608608
)
609609
logger.info(
610-
f"Copied image {source_project}" f" to {destination_project}/{image_name}."
610+
f"Copied image {source_project}/{image_name}"
611+
f" to {destination_project}/{destination_folder}."
611612
)
612613

613614

@@ -1782,7 +1783,7 @@ def upload_videos_from_folder_to_project(
17821783
project_name,
17831784
exclude_file_patterns,
17841785
)
1785-
1786+
uploaded_paths = []
17861787
for path in video_paths:
17871788
with tempfile.TemporaryDirectory() as temp_path:
17881789
res = controller.extract_video_frames(
@@ -1807,28 +1808,34 @@ def upload_videos_from_folder_to_project(
18071808
)
18081809
images_to_upload, duplicates = use_case.images_to_upload
18091810
logger.info(
1810-
"Extracted %s frames from video. Now uploading to platform.",
1811-
len(res.data),
1811+
f"Extracted {len(res.data)} frames from video. Now uploading to platform.",
18121812
)
18131813
logger.info(
1814-
"Uploading %s images to project %s.",
1815-
len(images_to_upload),
1816-
str(project_folder_name),
1814+
f"Uploading {len(images_to_upload)} images to project {str(project_folder_name)}."
18171815
)
1816+
18181817
if len(duplicates):
18191818
logger.warning(
1820-
"%s already existing images found that won't be uploaded.",
1821-
len(duplicates),
1819+
f"{len(duplicates)} already existing images found that won't be uploaded."
18221820
)
1821+
18231822
if use_case.is_valid():
18241823
with tqdm(
18251824
total=len(images_to_upload), desc="Uploading images"
18261825
) as progress_bar:
18271826
for _ in use_case.execute():
1828-
progress_bar.update(1)
1827+
progress_bar.update()
1828+
uploaded, failed_images, duplicated = use_case.response.data
1829+
uploaded_paths.extend(uploaded)
1830+
if failed_images:
1831+
logger.warning(f"Failed {len(uploaded)}.")
1832+
if duplicated:
1833+
logger.warning(
1834+
f"{len(duplicated)} already existing images found that won't be uploaded."
1835+
)
18291836
else:
18301837
raise AppException(use_case.response.errors)
1831-
1838+
return uploaded_paths
18321839
return
18331840

18341841

src/superannotate/lib/core/plugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ def extract_frames(
224224
logger.info("Video frame count is %s.", frames_count)
225225

226226
fps = video.get(cv2.CAP_PROP_FPS)
227+
if not target_fps:
228+
target_fps = fps
227229
if target_fps > fps:
228230
logger.warning(
229231
"Video frame rate %s smaller than target frame rate %s. Cannot change frame rate.",

src/superannotate/lib/core/usecases.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,6 @@ def execute(self):
17951795

17961796

17971797
class AssignImagesUseCase(BaseUseCase):
1798-
17991798
CHUNK_SIZE = 500
18001799

18011800
def __init__(
@@ -1840,7 +1839,6 @@ def execute(self):
18401839

18411840

18421841
class UnAssignImagesUseCase(BaseUseCase):
1843-
18441842
CHUNK_SIZE = 500
18451843

18461844
def __init__(
@@ -1867,7 +1865,7 @@ def execute(self):
18671865
)
18681866
if not is_un_assigned:
18691867
self._response.errors = AppException(
1870-
f"Cant un assign {', '.join(self._image_names[i : i + self.CHUNK_SIZE])}"
1868+
f"Cant un assign {', '.join(self._image_names[i: i + self.CHUNK_SIZE])}"
18711869
)
18721870

18731871
return self._response
@@ -2834,7 +2832,6 @@ def execute(self):
28342832

28352833

28362834
class CreateAnnotationClassesUseCase(BaseUseCase):
2837-
28382835
CHUNK_SIZE = 500
28392836

28402837
def __init__(
@@ -3120,6 +3117,8 @@ def execute(self):
31203117
weight, height = image.get_size()
31213118
empty_image_arr = np.full((height, weight, 4), [0, 0, 0, 255], np.uint8)
31223119
for annotation in self.annotations["instances"]:
3120+
if not class_color_map.get(annotation["className"]):
3121+
continue
31233122
fill_color = *class_color_map[annotation["className"]], 255
31243123
for part in annotation["parts"]:
31253124
part_color = *self.generate_color(part["color"]), 255
@@ -3308,13 +3307,32 @@ def annotation_classes_name_map(self) -> dict:
33083307
for attribute_group in annotation_class.attribute_groups:
33093308
attribute_group_data = defaultdict(dict)
33103309
for attribute in attribute_group["attributes"]:
3310+
if attribute["name"] in attribute_group_data.keys():
3311+
logger.warning(
3312+
f"Duplicate annotation class attribute name {attribute['name']}"
3313+
f" in attribute group {attribute_group['name']}. "
3314+
"Only one of the annotation class attributes will be used. "
3315+
"This will result in errors in annotation upload."
3316+
)
33113317
attribute_group_data[attribute["name"]] = attribute["id"]
3318+
if attribute_group["name"] in class_info.keys():
3319+
logger.warning(
3320+
f"Duplicate annotation class attribute group name {attribute_group['name']}."
3321+
" Only one of the annotation class attribute groups will be used."
3322+
" This will result in errors in annotation upload."
3323+
)
33123324
class_info["attribute_groups"] = {
33133325
attribute_group["name"]: {
33143326
"id": attribute_group["id"],
33153327
"attributes": attribute_group_data,
33163328
}
33173329
}
3330+
if annotation_class.name in classes_data.keys():
3331+
logger.warning(
3332+
f"Duplicate annotation class name {annotation_class.name}."
3333+
f" Only one of the annotation classes will be used."
3334+
" This will result in errors in annotation upload.",
3335+
)
33183336
classes_data[annotation_class.name] = class_info
33193337
return classes_data
33203338

tests/integration/test_interface.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ def test_image_upload_with_set_name_on_platform(self):
167167
self.assertIn(sa.search_images(self.PROJECT_NAME)[0],self.NEW_IMAGE_NAME)
168168

169169

170+
def test_download_fuse_without_classes(self):
171+
sa.upload_image_to_project(self.PROJECT_NAME, f"{self.folder_path}/{self.EXAMPLE_IMAGE_1}")
172+
sa.upload_image_annotations(
173+
self.PROJECT_NAME, self.EXAMPLE_IMAGE_1, f"{self.folder_path}/{self.EXAMPLE_IMAGE_1}___objects.json"
174+
)
175+
with tempfile.TemporaryDirectory() as tmp_dir:
176+
result = sa.download_image(
177+
self.PROJECT_NAME,
178+
self.EXAMPLE_IMAGE_1,
179+
tmp_dir,
180+
include_annotations=True,
181+
include_fuse=True
182+
)
183+
pass
184+
170185

171186
class TestPixelInterface(BaseTestCase):
172187
PROJECT_NAME = "Interface test"

0 commit comments

Comments
 (0)