Skip to content

Commit ef02171

Browse files
authored
Merge pull request #23 from superannotateai/develop
Merge develop
2 parents 8ed5b22 + 15eaa30 commit ef02171

File tree

11 files changed

+283
-221
lines changed

11 files changed

+283
-221
lines changed

.pylintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ disable=
2323
no-else-return,
2424
too-many-lines,
2525
too-many-arguments,
26-
too-many-instance-attributes
26+
too-many-instance-attributes,
27+
broad-except
2728

2829
[SPELLING]
2930

superannotate/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def consensus(*args, **kwargs):
5050
download_image_preannotations, get_image_annotations, get_image_bytes,
5151
get_image_metadata, get_image_preannotations, search_images,
5252
search_images_all_folders, set_image_annotation_status,
53-
set_images_annotation_statuses, upload_image_annotations
53+
set_images_annotation_statuses, upload_image_annotations, get_project_root_folder_id
5454
)
5555
from .db.project_api import (
5656
create_folder, delete_folders, get_folder_metadata,

superannotate/common.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@
5151
"Failed": 4
5252
}
5353

54+
_MODEL_TRAINING_TASKS = {
55+
"Instance Segmentation for Pixel Projects" : "instance_segmentation_pixel",
56+
"Instance Segmentation for Vector Projects" : "instance_segmentation_vector",
57+
"Keypoint Detection for Vector Projects" : "keypoint_detection_vector",
58+
"Object Detection for Vector Projects" : "object_detection_vector",
59+
"Semantic Segmentation for Pixel Projects" : "semantic_segmentation_pixel"
60+
}
61+
5462

5563
def prediction_segmentation_status_from_str_to_int(status):
5664
return _PREDICTION_SEGMENTATION_STATUSES[status]

superannotate/db/images.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -231,30 +231,32 @@ def get_image_metadata(project, image_names, return_dict_on_single_output=True):
231231
else:
232232
project_folder_id = None
233233

234+
chunk_size = 500
235+
chunks = [image_names[i:i + chunk_size] for i in range(0, len(image_names), chunk_size)]
236+
234237
json_req = {
235238
'project_id': project['id'],
236239
'team_id': _api.team_id,
237-
'names': image_names,
238240
}
241+
239242
if project_folder_id is not None:
240243
json_req["folder_id"] = project_folder_id
241-
response = _api.send_request(
242-
req_type='POST',
243-
path='/images/getBulk',
244-
json_req=json_req,
245-
)
246-
if not response.ok:
247-
raise SABaseException(
248-
response.status_code,
249-
"Couldn't get image metadata. " + response.text
250-
)
251244

252-
metadata_raw = response.json()
245+
metadata_raw = []
246+
for chunk in chunks:
247+
json_req['names'] = chunk
248+
response = _api.send_request(
249+
req_type='POST',
250+
path='/images/getBulk',
251+
json_req=json_req,
252+
)
253+
if not response.ok:
254+
raise SABaseException(response.status_code,"Couldn't get image metadata. " + response.text)
255+
metadata_raw += response.json()
256+
253257
metadata_without_deleted = []
254-
for im_metadata in metadata_raw:
255-
if 'delete' in im_metadata and im_metadata['delete'] == 1:
256-
continue
257-
metadata_without_deleted.append(im_metadata)
258+
metadata_without_deleted = [ i for i in metadata_raw if i['delete'] != 1 ]
259+
258260
if len(metadata_without_deleted) == 0:
259261
raise SABaseException(
260262
0,

superannotate/db/project_images.py

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
from .project_api import get_project_and_folder_metadata
1818
from .projects import (
1919
__create_image, get_image_array_to_upload,
20-
get_project_default_image_quality_in_editor, upload_image_array_to_s3
20+
get_project_default_image_quality_in_editor, upload_image_array_to_s3,
21+
_get_available_image_counts
2122
)
23+
from .utils import _get_upload_auth_token
2224

2325
logger = logging.getLogger("superannotate-python-sdk")
2426
_api = API.get_instance()
@@ -50,7 +52,8 @@ def upload_image_to_project(
5052
Can be either "compressed" or "original". If None then the default value in project settings will be used.
5153
:type image_quality_in_editor: str
5254
"""
53-
project, project_folder = get_project_and_folder_metadata(project)
55+
initial_project_inp = project
56+
project, folder = get_project_and_folder_metadata(project)
5457
upload_state = common.upload_state_int_to_str(project.get("upload_state"))
5558
if upload_state == "External":
5659
raise SABaseException(
@@ -92,20 +95,14 @@ def upload_image_to_project(
9295
0, "Image name img_name should be set if img is not Pathlike"
9396
)
9497

98+
if folder:
99+
folder_id = folder["id"]
100+
else:
101+
folder_id = get_project_root_folder_id(project)
102+
95103
team_id, project_id = project["team_id"], project["id"]
96-
params = {
97-
'team_id': team_id,
98-
}
99-
response = _api.send_request(
100-
req_type='GET',
101-
path=f'/project/{project_id}/sdkImageUploadToken',
102-
params=params
103-
)
104-
if not response.ok:
105-
raise SABaseException(
106-
response.status_code, "Couldn't get upload token " + response.text
107-
)
108-
res = response.json()
104+
params = {'team_id': team_id, 'folder_id': folder_id}
105+
res = _get_upload_auth_token(params=params, project_id=project_id)
109106
prefix = res['filePath']
110107
s3_session = boto3.Session(
111108
aws_access_key_id=res['accessKeyId'],
@@ -120,24 +117,20 @@ def upload_image_to_project(
120117
)
121118
key = upload_image_array_to_s3(bucket, *images_info_and_array, prefix)
122119
except Exception as e:
123-
raise SABaseException(0, "Couldn't upload to data server. " + str(e))
120+
raise SABaseException(0, "Couldn't upload to data server.") from e
124121

125-
if project_folder is not None:
126-
project_folder_id = project_folder["id"]
127-
else:
128-
project_folder_id = None
129122
__create_image(
130123
[img_name], [key],
131124
project,
132125
annotation_status,
133126
prefix, [images_info_and_array[2]],
134-
project_folder_id,
127+
folder_id,
135128
upload_state="Basic"
136129
)
137130

138131
while True:
139132
try:
140-
get_image_metadata(project, img_name)
133+
get_image_metadata(initial_project_inp, img_name)
141134
except SABaseException:
142135
time.sleep(0.2)
143136
else:
@@ -171,7 +164,8 @@ def _copy_images(
171164
destination_folder_id = get_project_root_folder_id(destination_project)
172165
json_req["destination_folder_id"] = destination_folder_id
173166
res = {}
174-
res['skipped'] = 0
167+
res['skipped'] = []
168+
res['completed'] = []
175169
for start_index in range(0, len(image_names), NUM_TO_SEND):
176170
json_req["image_names"] = image_names[start_index:start_index +
177171
NUM_TO_SEND]
@@ -187,6 +181,7 @@ def _copy_images(
187181
response.status_code, "Couldn't copy images " + response.text
188182
)
189183
res['skipped'] += response.json()['skipped']
184+
res['completed'] += response.json()['completed']
190185

191186
for image_name in image_names:
192187
_copy_annotations_and_metadata(
@@ -219,6 +214,8 @@ def copy_images(
219214
:type copy_annotation_status: bool
220215
:param copy_pin: enables image pin status copy
221216
:type copy_pin: bool
217+
:return: list of skipped image names
218+
:rtype: list of strs
222219
"""
223220
source_project, source_project_folder = get_project_and_folder_metadata(
224221
source_project
@@ -228,20 +225,30 @@ def copy_images(
228225
)
229226
if image_names is None:
230227
image_names = search_images((source_project, source_project_folder))
228+
229+
limit = _get_available_image_counts(
230+
destination_project, destination_project_folder
231+
)
232+
imgs_to_upload = image_names[:limit]
231233
res = _copy_images(
232234
(source_project, source_project_folder),
233-
(destination_project, destination_project_folder), image_names,
235+
(destination_project, destination_project_folder), imgs_to_upload,
234236
include_annotations, copy_annotation_status, copy_pin
235237
)
238+
uploaded_imgs = res['completed']
239+
skipped_imgs = [i for i in imgs_to_upload if i not in uploaded_imgs]
240+
241+
skipped_images_count = len(skipped_imgs) + len(image_names[limit:])
242+
236243
logger.info(
237244
"Copied images %s from %s to %s. Number of skipped images %s",
238-
image_names,
239-
source_project["name"] + "" if source_project_folder is None else "/" +
240-
source_project_folder["name"], destination_project["name"] +
241-
"" if destination_project_folder is None else "/" +
242-
destination_project_folder["name"], res["skipped"]
245+
uploaded_imgs, source_project["name"] +
246+
"" if source_project_folder is None else source_project["name"] + "/" +
247+
source_project_folder["name"], destination_project["name"] + ""
248+
if destination_project_folder is None else destination_project["name"] +
249+
"/" + destination_project_folder["name"], skipped_images_count
243250
)
244-
return res["skipped"]
251+
return skipped_imgs
245252

246253

247254
def delete_images(project, image_names):
@@ -322,11 +329,9 @@ def move_images(
322329
)
323330
if image_names is None:
324331
image_names = search_images((source_project, source_project_folder))
325-
_copy_images(
326-
(source_project, source_project_folder),
327-
(destination_project, destination_project_folder), image_names,
328-
include_annotations, copy_annotation_status, copy_pin
329-
)
332+
copy_images((source_project, source_project_folder), image_names,
333+
(destination_project, destination_project_folder),
334+
include_annotations, copy_annotation_status, copy_pin)
330335
delete_images((source_project, source_project_folder), image_names)
331336
logger.info(
332337
"Moved images %s from project %s to project %s", image_names,

0 commit comments

Comments
 (0)