Skip to content

Commit e7a57db

Browse files
committed
thread tqdm and meta with height and width
1 parent 2973c4e commit e7a57db

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+969
-777
lines changed

superannotate/common.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import sys
66
import time
7+
from tqdm import tqdm
78
from pathlib import Path
89

910
import numpy as np
@@ -254,3 +255,17 @@ def write_to_json(output_path, json_data):
254255
"Vector": 100_000_000,
255256
"Pixel": 4_000_000
256257
} # Resolution limit
258+
259+
260+
def tqdm_converter(
261+
total_num, images_converted, images_not_converted, finish_event
262+
):
263+
with tqdm(total=total_num) as pbar:
264+
while True:
265+
finished = finish_event.wait(5)
266+
if not finished:
267+
sum_all = len(images_converted) + len(images_not_converted)
268+
pbar.update(sum_all - pbar.n)
269+
else:
270+
pbar.update(total_num - pbar.n)
271+
break

superannotate/db/projects.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,24 @@ def upload_images_to_project(
842842
return (list_of_uploaded, list_of_not_uploaded, duplicate_images)
843843

844844

845+
def _tqdm_download(
846+
total_num, images_to_upload, images_not_uploaded,
847+
duplicate_images_filenames, finish_event
848+
):
849+
with tqdm(total=total_num) as pbar:
850+
while True:
851+
finished = finish_event.wait(1)
852+
if not finished:
853+
sum_all = 0
854+
sum_all += len(images_not_uploaded)
855+
sum_all += len(images_to_upload)
856+
sum_all += len(duplicate_images_filenames)
857+
pbar.update(sum_all - pbar.n)
858+
else:
859+
pbar.update(total_num - pbar.n)
860+
break
861+
862+
845863
def upload_images_from_public_urls_to_project(
846864
project,
847865
img_urls,
@@ -875,6 +893,18 @@ def upload_images_from_public_urls_to_project(
875893
images_to_upload = []
876894
duplicate_images_filenames = []
877895
path_to_url = {}
896+
897+
finish_event = threading.Event()
898+
tqdm_thread = threading.Thread(
899+
target=_tqdm_download,
900+
args=(
901+
len(img_urls), images_to_upload, images_not_uploaded,
902+
duplicate_images_filenames, finish_event
903+
),
904+
daemon=True
905+
)
906+
logger.info('Downloading %s images' % len(img_urls))
907+
tqdm_thread.start()
878908
with tempfile.TemporaryDirectory() as save_dir_name:
879909
save_dir = Path(save_dir_name)
880910
for i, img_url in enumerate(img_urls):
@@ -906,6 +936,9 @@ def upload_images_from_public_urls_to_project(
906936

907937
path_to_url[str(img_path)] = img_url
908938
images_to_upload.append(img_path)
939+
940+
finish_event.set()
941+
tqdm_thread.join()
909942
images_uploaded_paths, images_not_uploaded_paths, duplicate_images_paths = upload_images_to_project(
910943
project,
911944
images_to_upload,

superannotate/input_converters/conversion.py

Lines changed: 89 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -75,42 +75,40 @@
7575
}
7676

7777

78-
def _passes_sanity_checks(args):
79-
if not isinstance(args.input_dir, (str, Path)):
80-
raise SABaseException(
81-
0, "'input_dir' should be 'str' or 'Path' type, not '%s'" %
82-
(type(args.input_dir))
83-
)
78+
def _change_type(input_dir, output_dir):
79+
if isinstance(input_dir, str):
80+
input_dir = Path(input_dir)
81+
if isinstance(output_dir, str):
82+
output_dir = Path(output_dir)
83+
return input_dir, output_dir
8484

85-
if not isinstance(args.output_dir, (str, Path)):
86-
raise SABaseException(
87-
0, "'output_dir' should be 'str' or 'Path' type, not {}".format(
88-
type(args.output_dir)
85+
86+
def _passes_type_sanity(params_info):
87+
for param in params_info:
88+
if not isinstance(param[0], param[2]):
89+
raise SABaseException(
90+
0, "'%s' should be %s type, not %s" %
91+
(param[1], param[2], type(param[0]))
8992
)
90-
)
9193

92-
if args.dataset_format not in ALLOWED_ANNOTATION_IMPORT_FORMATS.keys():
93-
raise SABaseException(
94-
0, "'%s' converter doesn't exist. Possible candidates are '%s'" %
95-
(args.dataset_format, ALLOWED_ANNOTATION_IMPORT_FORMATS.keys())
96-
)
9794

98-
if not isinstance(args.dataset_name, str):
99-
raise SABaseException(
100-
0, "'dataset_name' should be 'str' type, not {}".format(
101-
type(args.dataset_name)
102-
)
103-
)
95+
def _passes_list_members_type_sanity(lists_info):
96+
for _list in lists_info:
97+
for _list_member in _list[0]:
98+
if not isinstance(_list_member, _list[2]):
99+
raise SABaseException(
100+
0, "'%s' should be list of '%s', but contains '%s'" %
101+
(_list[1], _list[2], type(_list_member))
102+
)
104103

105-
if args.project_type not in ALLOWED_PROJECT_TYPES:
106-
raise SABaseException(
107-
0, "Please enter valid project type: 'Pixel' or 'Vector'"
108-
)
109104

110-
if args.task not in ALLOWED_TASK_TYPES:
111-
raise SABaseException(
112-
0, "Please enter valid task '%s'" % (ALLOWED_TASK_TYPES)
113-
)
105+
def _passes_value_sanity(values_info):
106+
for value in values_info:
107+
if value[0] not in value[2]:
108+
raise SABaseException(
109+
0, "'%s' should be one of the following '%s'" %
110+
(value[1], value[2])
111+
)
114112

115113

116114
def _passes_converter_sanity(args, direction):
@@ -177,10 +175,25 @@ def export_annotation(
177175
178176
"""
179177

180-
if isinstance(input_dir, str):
181-
input_dir = Path(input_dir)
182-
if isinstance(output_dir, str):
183-
output_dir = Path(output_dir)
178+
params_info = [
179+
(input_dir, 'input_dir', (str, Path)),
180+
(output_dir, 'output_dir', (str, Path)),
181+
(dataset_name, 'dataset_name', str),
182+
(dataset_format, 'dataset_format', str),
183+
(project_type, 'project_type', str), (task, 'task', str)
184+
]
185+
_passes_type_sanity(params_info)
186+
input_dir, output_dir = _change_type(input_dir, output_dir)
187+
188+
values_info = [
189+
(project_type, 'project_type', ALLOWED_PROJECT_TYPES),
190+
(task, 'task', ALLOWED_TASK_TYPES),
191+
(
192+
dataset_format, 'dataset_format',
193+
list(ALLOWED_ANNOTATION_EXPORT_FORMATS.keys())
194+
)
195+
]
196+
_passes_value_sanity(values_info)
184197

185198
args = Namespace(
186199
input_dir=input_dir,
@@ -191,7 +204,6 @@ def export_annotation(
191204
task=task,
192205
)
193206

194-
_passes_sanity_checks(args)
195207
_passes_converter_sanity(args, 'export')
196208

197209
export_from_sa(args)
@@ -205,7 +217,7 @@ def import_annotation(
205217
project_type="Vector",
206218
task="object_detection",
207219
images_root='',
208-
images_extensions=['jpg']
220+
images_extensions=None
209221
):
210222
"""Converts other annotation formats to SuperAnnotate annotation format. Currently available (project_type, task) combinations for converter
211223
presented below:
@@ -337,11 +349,31 @@ def import_annotation(
337349
338350
"""
339351

340-
if isinstance(input_dir, str):
341-
input_dir = Path(input_dir)
342-
if isinstance(output_dir, str):
343-
output_dir = Path(output_dir)
352+
params_info = [
353+
(input_dir, 'input_dir', (str, Path)),
354+
(output_dir, 'output_dir', (str, Path)),
355+
(dataset_name, 'dataset_name', str),
356+
(dataset_format, 'dataset_format', str),
357+
(project_type, 'project_type', str), (task, 'task', str),
358+
(images_root, 'images_root', str)
359+
]
360+
361+
if images_extensions is not None:
362+
params_info.append((images_extensions, 'image_extensions', list))
363+
364+
_passes_type_sanity(params_info)
365+
366+
values_info = [
367+
(project_type, 'project_type', ALLOWED_PROJECT_TYPES),
368+
(task, 'task', ALLOWED_TASK_TYPES),
369+
(
370+
dataset_format, 'dataset_format',
371+
list(ALLOWED_ANNOTATION_IMPORT_FORMATS.keys())
372+
)
373+
]
374+
_passes_value_sanity(values_info)
344375

376+
input_dir, output_dir = _change_type(input_dir, output_dir)
345377
args = Namespace(
346378
input_dir=input_dir,
347379
output_dir=output_dir,
@@ -353,7 +385,6 @@ def import_annotation(
353385
images_extensions=images_extensions
354386
)
355387

356-
_passes_sanity_checks(args)
357388
_passes_converter_sanity(args, 'import')
358389

359390
import_to_sa(args)
@@ -368,17 +399,12 @@ def convert_project_type(input_dir, output_dir):
368399
:type output_dir: Pathlike(str or Path)
369400
370401
"""
371-
param_info = [
402+
params_info = [
372403
(input_dir, 'input_dir', (str, Path)),
373404
(output_dir, 'output_dir', (str, Path)),
374405
]
375-
for param in param_info:
376-
_type_sanity(param[0], param[1], param[2])
377-
378-
if isinstance(input_dir, str):
379-
input_dir = Path(input_dir)
380-
if isinstance(output_dir, str):
381-
output_dir = Path(output_dir)
406+
_passes_type_sanity(params_info)
407+
input_dir, output_dir = _change_type(input_dir, output_dir)
382408

383409
sa_convert_project_type(input_dir, output_dir)
384410

@@ -399,40 +425,32 @@ def coco_split_dataset(
399425
:param ratio_list: List of ratios for each splitted dataset.
400426
:type ratio_list: list
401427
"""
402-
param_info = [
428+
params_info = [
403429
(coco_json_path, 'coco_json_path', (str, Path)),
404430
(image_dir, 'image_dir', (str, Path)),
405431
(output_dir, 'output_dir', (str, Path)),
406432
(dataset_list_name, 'dataset_list_name', list),
407433
(ratio_list, 'ratio_list', list)
408434
]
409-
for param in param_info:
410-
_type_sanity(param[0], param[1], param[2])
435+
_passes_type_sanity(params_info)
411436

412-
for dataset_name in dataset_list_name:
413-
if not isinstance(dataset_name, (str, Path)):
414-
raise SABaseException(
415-
0,
416-
"'dataset_list_name' member should be 'str' or 'Path' type, not '%s'"
417-
% (type(dataset_name))
418-
)
437+
lists_info = [
438+
(dataset_list_name, 'dataset_name', str),
439+
(ratio_list, 'ratio_list', (int, float))
440+
]
419441

420-
for ratio in ratio_list:
421-
if not isinstance(ratio, (int, float)):
422-
raise SABaseException(
423-
0,
424-
"'ratio_list' member should be 'int' or 'float' type, not '%s'"
425-
% (type(ratio))
426-
)
442+
_passes_list_members_type_sanity(lists_info)
427443

428444
if sum(ratio_list) != 100:
429-
raise SABaseException(0, "Sum of 'ratio_list' members must be '100'")
445+
raise SABaseException(0, "Sum of 'ratio_list' members must be 100")
430446

431447
if len(dataset_list_name) != len(ratio_list):
432448
raise SABaseException(
433449
0, "'dataset_list_name' and 'ratio_list' should have same lenght"
434450
)
435451

452+
if isinstance(coco_json_path, str):
453+
coco_json_path = Path(coco_json_path)
436454
if isinstance(image_dir, str):
437455
image_dir = Path(image_dir)
438456
if isinstance(output_dir, str):
@@ -443,15 +461,6 @@ def coco_split_dataset(
443461
)
444462

445463

446-
def _type_sanity(var, var_name, var_type):
447-
if not isinstance(var, var_type):
448-
raise SABaseException(
449-
0, "'{}' should be '{}' type, not '{}'".format(
450-
var_name, var_type, type(var)
451-
)
452-
)
453-
454-
455464
def convert_json_version(input_dir, output_dir, version=2):
456465
"""
457466
Converts SuperAnnotate JSON versions. Newest JSON version is 2.
@@ -466,19 +475,15 @@ def convert_json_version(input_dir, output_dir, version=2):
466475
:return: List of converted files
467476
:rtype: list
468477
"""
469-
param_info = [
478+
479+
params_info = [
470480
(input_dir, 'input_dir', (str, Path)),
471481
(output_dir, 'output_dir', (str, Path)), (version, 'version', int)
472482
]
473-
for param in param_info:
474-
_type_sanity(param[0], param[1], param[2])
483+
_passes_type_sanity(params_info)
484+
input_dir, output_dir = _change_type(input_dir, output_dir)
475485

476-
if isinstance(input_dir, str):
477-
input_dir = Path(input_dir)
478-
if isinstance(output_dir, str):
479-
output_dir = Path(output_dir)
480486
output_dir.mkdir(parents=True, exist_ok=True)
481-
482487
if version == 2:
483488
converted_files = upgrade_json(input_dir, output_dir)
484489
elif version == 1:

0 commit comments

Comments
 (0)