datamint 1.4.0__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of datamint might be problematic. Click here for more details.
- {datamint-1.4.0 → datamint-1.5.0}/PKG-INFO +1 -1
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/annotation_api_handler.py +288 -65
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/root_api_handler.py +227 -101
- datamint-1.5.0/datamint/client_cmd_tools/datamint_config.py +211 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/client_cmd_tools/datamint_upload.py +34 -21
- {datamint-1.4.0 → datamint-1.5.0}/datamint/experiment/experiment.py +1 -1
- {datamint-1.4.0 → datamint-1.5.0}/datamint/utils/dicom_utils.py +12 -12
- {datamint-1.4.0 → datamint-1.5.0}/datamint/utils/io_utils.py +37 -10
- {datamint-1.4.0 → datamint-1.5.0}/pyproject.toml +1 -1
- datamint-1.4.0/datamint/client_cmd_tools/datamint_config.py +0 -168
- {datamint-1.4.0 → datamint-1.5.0}/README.md +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/__init__.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/api_handler.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/base_api_handler.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/dto/annotation_dto.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/apihandler/exp_api_handler.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/client_cmd_tools/__init__.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/configs.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/dataset/__init__.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/dataset/base_dataset.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/dataset/dataset.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/examples/__init__.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/examples/example_projects.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/experiment/__init__.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/experiment/_patcher.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/logging.yaml +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/utils/logging_utils.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/utils/torchmetrics.py +0 -0
- {datamint-1.4.0 → datamint-1.5.0}/datamint/utils/visualization.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: datamint
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: A library for interacting with the Datamint API, designed for efficient data management, processing and Deep Learning workflows.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -88,41 +88,39 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
88
88
|
raise DatamintException(r['error'])
|
|
89
89
|
return resp
|
|
90
90
|
|
|
91
|
-
async def
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
model_id=model_id)
|
|
120
|
-
annotids.extend(reti)
|
|
121
|
-
return annotids
|
|
91
|
+
async def _upload_single_frame_segmentation_async(self,
|
|
92
|
+
resource_id: str,
|
|
93
|
+
frame_index: int,
|
|
94
|
+
fio: IO,
|
|
95
|
+
name: Optional[str | dict[int, str]] = None,
|
|
96
|
+
imported_from: Optional[str] = None,
|
|
97
|
+
author_email: Optional[str] = None,
|
|
98
|
+
discard_empty_segmentations: bool = True,
|
|
99
|
+
worklist_id: Optional[str] = None,
|
|
100
|
+
model_id: Optional[str] = None
|
|
101
|
+
) -> list[str]:
|
|
102
|
+
"""
|
|
103
|
+
Upload a single frame segmentation asynchronously.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
resource_id: The resource unique id.
|
|
107
|
+
frame_index: The frame index for the segmentation.
|
|
108
|
+
fio: File-like object containing the segmentation image.
|
|
109
|
+
name: The name of the segmentation or a dictionary mapping pixel values to names.
|
|
110
|
+
imported_from: The imported from value.
|
|
111
|
+
author_email: The author email.
|
|
112
|
+
discard_empty_segmentations: Whether to discard empty segmentations.
|
|
113
|
+
worklist_id: The annotation worklist unique id.
|
|
114
|
+
model_id: The model unique id.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
List of annotation IDs created.
|
|
118
|
+
"""
|
|
122
119
|
try:
|
|
123
120
|
try:
|
|
124
121
|
img = np.array(Image.open(fio))
|
|
125
|
-
|
|
122
|
+
|
|
123
|
+
# Check that frame is not empty
|
|
126
124
|
uniq_vals = np.unique(img)
|
|
127
125
|
if discard_empty_segmentations:
|
|
128
126
|
if len(uniq_vals) == 1 and uniq_vals[0] == 0:
|
|
@@ -135,31 +133,38 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
135
133
|
|
|
136
134
|
segnames = AnnotationAPIHandler._get_segmentation_names(uniq_vals, names=name)
|
|
137
135
|
segs_generator = AnnotationAPIHandler._split_segmentations(img, uniq_vals, fio)
|
|
136
|
+
|
|
137
|
+
# Create annotations
|
|
138
138
|
annotations: list[CreateAnnotationDto] = []
|
|
139
139
|
for segname in segnames:
|
|
140
|
-
ann = CreateAnnotationDto(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
ann = CreateAnnotationDto(
|
|
141
|
+
type='segmentation',
|
|
142
|
+
identifier=segname,
|
|
143
|
+
scope='frame',
|
|
144
|
+
frame_index=frame_index,
|
|
145
|
+
imported_from=imported_from,
|
|
146
|
+
import_author=author_email,
|
|
147
|
+
model_id=model_id,
|
|
148
|
+
annotation_worklist_id=worklist_id
|
|
149
|
+
)
|
|
148
150
|
annotations.append(ann)
|
|
149
|
-
|
|
151
|
+
|
|
152
|
+
# Validate unique identifiers
|
|
150
153
|
if len(annotations) != len(set([a.identifier for a in annotations])):
|
|
151
154
|
raise ValueError(
|
|
152
|
-
"Multiple annotations with the same identifier, frame_index, scope and author is not supported yet."
|
|
155
|
+
"Multiple annotations with the same identifier, frame_index, scope and author is not supported yet."
|
|
156
|
+
)
|
|
153
157
|
|
|
154
158
|
annotids = await self._upload_annotations_async(resource_id, annotations)
|
|
155
159
|
|
|
156
|
-
|
|
160
|
+
# Upload segmentation files
|
|
157
161
|
if len(annotids) != len(segnames):
|
|
158
162
|
_LOGGER.warning(f"Number of uploaded annotations ({len(annotids)})" +
|
|
159
163
|
f" does not match the number of annotations ({len(segnames)})")
|
|
160
|
-
|
|
164
|
+
|
|
165
|
+
for annotid, segname, fio_seg in zip(annotids, segnames, segs_generator):
|
|
161
166
|
form = aiohttp.FormData()
|
|
162
|
-
form.add_field('file',
|
|
167
|
+
form.add_field('file', fio_seg, filename=segname, content_type='image/png')
|
|
163
168
|
request_params = dict(
|
|
164
169
|
method='POST',
|
|
165
170
|
url=f'{self.root_url}/annotations/{resource_id}/annotations/{annotid}/file',
|
|
@@ -168,19 +173,226 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
168
173
|
resp = await self._run_request_async(request_params)
|
|
169
174
|
if 'error' in resp:
|
|
170
175
|
raise DatamintException(resp['error'])
|
|
171
|
-
|
|
176
|
+
|
|
177
|
+
return annotids
|
|
172
178
|
finally:
|
|
173
179
|
fio.close()
|
|
174
|
-
_USER_LOGGER.info(f'Segmentations uploaded for resource {resource_id}')
|
|
175
|
-
return annotids
|
|
176
180
|
except ResourceNotFoundError:
|
|
177
181
|
raise ResourceNotFoundError('resource', {'resource_id': resource_id})
|
|
178
182
|
|
|
183
|
+
async def _upload_volume_segmentation_async(self,
|
|
184
|
+
resource_id: str,
|
|
185
|
+
file_path: str | np.ndarray,
|
|
186
|
+
name: Optional[str] = None,
|
|
187
|
+
imported_from: Optional[str] = None,
|
|
188
|
+
author_email: Optional[str] = None,
|
|
189
|
+
worklist_id: Optional[str] = None,
|
|
190
|
+
model_id: Optional[str] = None,
|
|
191
|
+
transpose_segmentation: bool = False
|
|
192
|
+
) -> list[str]:
|
|
193
|
+
"""
|
|
194
|
+
Upload a volume segmentation as a single file asynchronously.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
resource_id: The resource unique id.
|
|
198
|
+
file_path: Path to segmentation file or numpy array.
|
|
199
|
+
name: The name of the segmentation (string only for volumes).
|
|
200
|
+
imported_from: The imported from value.
|
|
201
|
+
author_email: The author email.
|
|
202
|
+
worklist_id: The annotation worklist unique id.
|
|
203
|
+
model_id: The model unique id.
|
|
204
|
+
transpose_segmentation: Whether to transpose the segmentation.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
List of annotation IDs created.
|
|
208
|
+
|
|
209
|
+
Raises:
|
|
210
|
+
ValueError: If name is not a string or file format is unsupported for volume upload.
|
|
211
|
+
"""
|
|
212
|
+
if isinstance(name, dict):
|
|
213
|
+
raise ValueError("Volume uploads only support string names, not dictionaries.")
|
|
214
|
+
|
|
215
|
+
if name is None:
|
|
216
|
+
name = 'volume_segmentation'
|
|
217
|
+
|
|
218
|
+
# Create volume annotation
|
|
219
|
+
ann = CreateAnnotationDto(
|
|
220
|
+
type='segmentation',
|
|
221
|
+
identifier=name,
|
|
222
|
+
scope='frame', # Volume segmentations use image scope
|
|
223
|
+
imported_from=imported_from,
|
|
224
|
+
import_author=author_email,
|
|
225
|
+
model_id=model_id,
|
|
226
|
+
annotation_worklist_id=worklist_id
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
annotids = await self._upload_annotations_async(resource_id, [ann])
|
|
230
|
+
_LOGGER.debug(f"Created volume annotation with ID: {annotids}")
|
|
231
|
+
|
|
232
|
+
if not annotids:
|
|
233
|
+
raise DatamintException("Failed to create volume annotation")
|
|
234
|
+
|
|
235
|
+
annotid = annotids[0]
|
|
236
|
+
|
|
237
|
+
# Prepare file for upload
|
|
238
|
+
if isinstance(file_path, str):
|
|
239
|
+
if file_path.endswith('.nii') or file_path.endswith('.nii.gz'):
|
|
240
|
+
content_type = 'application/x-nifti'
|
|
241
|
+
# Upload NIfTI file directly
|
|
242
|
+
with open(file_path, 'rb') as f:
|
|
243
|
+
filename = os.path.basename(file_path)
|
|
244
|
+
form = aiohttp.FormData()
|
|
245
|
+
form.add_field('file', f, filename=filename, content_type='application/x-nifti')
|
|
246
|
+
|
|
247
|
+
request_params = dict(
|
|
248
|
+
method='POST',
|
|
249
|
+
url=f'{self.root_url}/annotations/{resource_id}/annotations/{annotid}/file',
|
|
250
|
+
data=form,
|
|
251
|
+
)
|
|
252
|
+
resp = await self._run_request_async(request_params)
|
|
253
|
+
if 'error' in resp:
|
|
254
|
+
raise DatamintException(resp['error'])
|
|
255
|
+
else:
|
|
256
|
+
raise ValueError(f"Volume upload not supported for file format: {file_path}")
|
|
257
|
+
elif isinstance(file_path, np.ndarray):
|
|
258
|
+
# Convert numpy array to NIfTI and upload
|
|
259
|
+
# TODO: Consider supporting direct numpy array upload or convert to a supported format
|
|
260
|
+
if transpose_segmentation:
|
|
261
|
+
volume_data = file_path.transpose(1, 0, 2) if file_path.ndim == 3 else file_path.transpose(1, 0)
|
|
262
|
+
else:
|
|
263
|
+
volume_data = file_path
|
|
264
|
+
|
|
265
|
+
# Create temporary NIfTI file
|
|
266
|
+
import tempfile
|
|
267
|
+
with tempfile.NamedTemporaryFile(suffix='.nii.gz', delete=False) as tmp_file:
|
|
268
|
+
nii_img = nib.Nifti1Image(volume_data.astype(np.uint8), np.eye(4))
|
|
269
|
+
nib.save(nii_img, tmp_file.name)
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
with open(tmp_file.name, 'rb') as f:
|
|
273
|
+
form = aiohttp.FormData()
|
|
274
|
+
form.add_field('file', f, filename=f'{name}.nii.gz', content_type='application/x-nifti')
|
|
275
|
+
|
|
276
|
+
request_params = dict(
|
|
277
|
+
method='POST',
|
|
278
|
+
url=f'{self.root_url}/annotations/{resource_id}/annotations/{annotid}/file',
|
|
279
|
+
data=form,
|
|
280
|
+
)
|
|
281
|
+
resp = await self._run_request_async(request_params)
|
|
282
|
+
if 'error' in resp:
|
|
283
|
+
raise DatamintException(resp['error'])
|
|
284
|
+
finally:
|
|
285
|
+
os.unlink(tmp_file.name) # Clean up temporary file
|
|
286
|
+
else:
|
|
287
|
+
raise ValueError(f"Unsupported file_path type for volume upload: {type(file_path)}")
|
|
288
|
+
|
|
289
|
+
_USER_LOGGER.info(f'Volume segmentation uploaded for resource {resource_id}')
|
|
290
|
+
return annotids
|
|
291
|
+
|
|
292
|
+
async def _upload_segmentations_async(self,
|
|
293
|
+
resource_id: str,
|
|
294
|
+
frame_index: int | None,
|
|
295
|
+
file_path: str | np.ndarray | None = None,
|
|
296
|
+
fio: IO | None = None,
|
|
297
|
+
name: Optional[str | dict[int, str]] = None,
|
|
298
|
+
imported_from: Optional[str] = None,
|
|
299
|
+
author_email: Optional[str] = None,
|
|
300
|
+
discard_empty_segmentations: bool = True,
|
|
301
|
+
worklist_id: Optional[str] = None,
|
|
302
|
+
model_id: Optional[str] = None,
|
|
303
|
+
transpose_segmentation: bool = False,
|
|
304
|
+
upload_volume: bool | str = 'auto'
|
|
305
|
+
) -> list[str]:
|
|
306
|
+
"""
|
|
307
|
+
Upload segmentations asynchronously.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
resource_id: The resource unique id.
|
|
311
|
+
frame_index: The frame index or None for multiple frames.
|
|
312
|
+
file_path: Path to segmentation file or numpy array.
|
|
313
|
+
fio: File-like object containing segmentation data.
|
|
314
|
+
name: The name of the segmentation or mapping of pixel values to names.
|
|
315
|
+
imported_from: The imported from value.
|
|
316
|
+
author_email: The author email.
|
|
317
|
+
discard_empty_segmentations: Whether to discard empty segmentations.
|
|
318
|
+
worklist_id: The annotation worklist unique id.
|
|
319
|
+
model_id: The model unique id.
|
|
320
|
+
transpose_segmentation: Whether to transpose the segmentation.
|
|
321
|
+
upload_volume: Whether to upload the volume as a single file or split into frames.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
List of annotation IDs created.
|
|
325
|
+
"""
|
|
326
|
+
if upload_volume == 'auto':
|
|
327
|
+
if file_path is not None and (file_path.endswith('.nii') or file_path.endswith('.nii.gz')):
|
|
328
|
+
upload_volume = True
|
|
329
|
+
else:
|
|
330
|
+
upload_volume = False
|
|
331
|
+
|
|
332
|
+
if file_path is not None:
|
|
333
|
+
# Handle volume upload
|
|
334
|
+
if upload_volume:
|
|
335
|
+
if frame_index is not None:
|
|
336
|
+
_LOGGER.warning("frame_index parameter ignored when upload_volume=True")
|
|
337
|
+
|
|
338
|
+
return await self._upload_volume_segmentation_async(
|
|
339
|
+
resource_id=resource_id,
|
|
340
|
+
file_path=file_path,
|
|
341
|
+
name=name if isinstance(name, str) else None,
|
|
342
|
+
imported_from=imported_from,
|
|
343
|
+
author_email=author_email,
|
|
344
|
+
worklist_id=worklist_id,
|
|
345
|
+
model_id=model_id,
|
|
346
|
+
transpose_segmentation=transpose_segmentation
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# Handle frame-by-frame upload (existing logic)
|
|
350
|
+
nframes, fios = AnnotationAPIHandler._generate_segmentations_ios(
|
|
351
|
+
file_path, transpose_segmentation=transpose_segmentation
|
|
352
|
+
)
|
|
353
|
+
if frame_index is None:
|
|
354
|
+
frame_index = list(range(nframes))
|
|
355
|
+
|
|
356
|
+
annotids = []
|
|
357
|
+
for fidx, f in zip(frame_index, fios):
|
|
358
|
+
frame_annotids = await self._upload_single_frame_segmentation_async(
|
|
359
|
+
resource_id=resource_id,
|
|
360
|
+
frame_index=fidx,
|
|
361
|
+
fio=f,
|
|
362
|
+
name=name,
|
|
363
|
+
imported_from=imported_from,
|
|
364
|
+
author_email=author_email,
|
|
365
|
+
discard_empty_segmentations=discard_empty_segmentations,
|
|
366
|
+
worklist_id=worklist_id,
|
|
367
|
+
model_id=model_id
|
|
368
|
+
)
|
|
369
|
+
annotids.extend(frame_annotids)
|
|
370
|
+
return annotids
|
|
371
|
+
|
|
372
|
+
# Handle single file-like object
|
|
373
|
+
if fio is not None:
|
|
374
|
+
if upload_volume:
|
|
375
|
+
raise ValueError("upload_volume=True is not supported when providing fio parameter")
|
|
376
|
+
|
|
377
|
+
return await self._upload_single_frame_segmentation_async(
|
|
378
|
+
resource_id=resource_id,
|
|
379
|
+
frame_index=frame_index,
|
|
380
|
+
fio=fio,
|
|
381
|
+
name=name,
|
|
382
|
+
imported_from=imported_from,
|
|
383
|
+
author_email=author_email,
|
|
384
|
+
discard_empty_segmentations=discard_empty_segmentations,
|
|
385
|
+
worklist_id=worklist_id,
|
|
386
|
+
model_id=model_id
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
raise ValueError("Either file_path or fio must be provided")
|
|
390
|
+
|
|
179
391
|
def upload_segmentations(self,
|
|
180
392
|
resource_id: str,
|
|
181
393
|
file_path: str | np.ndarray,
|
|
182
394
|
name: Optional[str | dict[int, str]] = None,
|
|
183
|
-
frame_index: int | list[int] = None,
|
|
395
|
+
frame_index: int | list[int] | None = None,
|
|
184
396
|
imported_from: Optional[str] = None,
|
|
185
397
|
author_email: Optional[str] = None,
|
|
186
398
|
discard_empty_segmentations: bool = True,
|
|
@@ -195,13 +407,15 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
195
407
|
resource_id (str): The resource unique id.
|
|
196
408
|
file_path (str|np.ndarray): The path to the segmentation file or a numpy array.
|
|
197
409
|
If a numpy array is provided, it must have the shape (height, width, #frames) or (height, width).
|
|
410
|
+
For NIfTI files (.nii/.nii.gz), the entire volume is uploaded as a single segmentation.
|
|
198
411
|
name (Optional[Union[str, Dict[int, str]]]): The name of the segmentation or a dictionary mapping pixel values to names.
|
|
199
|
-
example: {1: 'Femur', 2: 'Tibia'}.
|
|
412
|
+
example: {1: 'Femur', 2: 'Tibia'}. For NIfTI files, only string names are supported.
|
|
200
413
|
frame_index (int | list[int]): The frame index of the segmentation.
|
|
201
414
|
If a list, it must have the same length as the number of frames in the segmentation.
|
|
202
415
|
If None, it is assumed that the segmentations are in sequential order starting from 0.
|
|
203
|
-
|
|
416
|
+
This parameter is ignored for NIfTI files as they are treated as volume segmentations.
|
|
204
417
|
discard_empty_segmentations (bool): Whether to discard empty segmentations or not.
|
|
418
|
+
This is ignored for NIfTI files.
|
|
205
419
|
|
|
206
420
|
Returns:
|
|
207
421
|
str: The segmentation unique id.
|
|
@@ -211,9 +425,32 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
211
425
|
|
|
212
426
|
Example:
|
|
213
427
|
>>> api_handler.upload_segmentation(resource_id, 'path/to/segmentation.png', 'SegmentationName')
|
|
428
|
+
>>> api_handler.upload_segmentation(resource_id, 'path/to/segmentation.nii.gz', 'VolumeSegmentation')
|
|
214
429
|
"""
|
|
215
430
|
if isinstance(file_path, str) and not os.path.exists(file_path):
|
|
216
431
|
raise FileNotFoundError(f"File {file_path} not found.")
|
|
432
|
+
|
|
433
|
+
# Handle NIfTI files specially - upload as single volume
|
|
434
|
+
if isinstance(file_path, str) and (file_path.endswith('.nii') or file_path.endswith('.nii.gz')):
|
|
435
|
+
_LOGGER.info(f"Uploading NIfTI segmentation file: {file_path}")
|
|
436
|
+
if frame_index is not None:
|
|
437
|
+
raise ValueError("Do not provide frame_index for NIfTI segmentations.")
|
|
438
|
+
loop = asyncio.get_event_loop()
|
|
439
|
+
task = self._upload_segmentations_async(
|
|
440
|
+
resource_id=resource_id,
|
|
441
|
+
frame_index=None,
|
|
442
|
+
file_path=file_path,
|
|
443
|
+
name=name,
|
|
444
|
+
imported_from=imported_from,
|
|
445
|
+
author_email=author_email,
|
|
446
|
+
discard_empty_segmentations=False,
|
|
447
|
+
worklist_id=worklist_id,
|
|
448
|
+
model_id=model_id,
|
|
449
|
+
transpose_segmentation=transpose_segmentation,
|
|
450
|
+
upload_volume=True
|
|
451
|
+
)
|
|
452
|
+
return loop.run_until_complete(task)
|
|
453
|
+
# All other file types are converted to multiple PNGs and uploaded frame by frame.
|
|
217
454
|
if isinstance(frame_index, int):
|
|
218
455
|
frame_index = [frame_index]
|
|
219
456
|
|
|
@@ -622,20 +859,6 @@ class AnnotationAPIHandler(BaseAPIHandler):
|
|
|
622
859
|
model_id=model_id
|
|
623
860
|
)
|
|
624
861
|
|
|
625
|
-
@deprecated(version='0.12.1', reason='Use :meth:`~get_annotations` instead with `resource_id` parameter.')
|
|
626
|
-
def get_resource_annotations(self,
|
|
627
|
-
resource_id: str,
|
|
628
|
-
annotation_type: Optional[str] = None,
|
|
629
|
-
annotator_email: Optional[str] = None,
|
|
630
|
-
date_from: Optional[date] = None,
|
|
631
|
-
date_to: Optional[date] = None) -> Generator[dict, None, None]:
|
|
632
|
-
|
|
633
|
-
return self.get_annotations(resource_id=resource_id,
|
|
634
|
-
annotation_type=annotation_type,
|
|
635
|
-
annotator_email=annotator_email,
|
|
636
|
-
date_from=date_from,
|
|
637
|
-
date_to=date_to)
|
|
638
|
-
|
|
639
862
|
def get_annotations(self,
|
|
640
863
|
resource_id: Optional[str] = None,
|
|
641
864
|
annotation_type: AnnotationType | str | None = None,
|