datamint 2.1.0__py3-none-any.whl → 2.1.2__py3-none-any.whl

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/api/base_api.py CHANGED
@@ -14,6 +14,7 @@ from io import BytesIO
14
14
  import gzip
15
15
  import contextlib
16
16
  import asyncio
17
+ from medimgkit.format_detection import GZIP_MIME_TYPES
17
18
 
18
19
  logger = logging.getLogger(__name__)
19
20
 
@@ -422,7 +423,7 @@ class BaseApi:
422
423
  if file_path is not None:
423
424
  return nib.load(file_path)
424
425
  raise e
425
- elif mimetype == 'application/gzip':
426
+ elif mimetype in GZIP_MIME_TYPES:
426
427
  # let's hope it's a .nii.gz
427
428
  with gzip.open(content_io, 'rb') as f:
428
429
  return nib.Nifti1Image.from_stream(f)
@@ -360,11 +360,13 @@ class DatamintBaseDataset:
360
360
  @property
361
361
  def segmentation_labels_set(self) -> list[str]:
362
362
  """Returns the set of segmentation labels in the dataset."""
363
- return self.frame_lsets['segmentation']
363
+ a = set(self.frame_lsets['segmentation'])
364
+ b = set(self.image_lsets['segmentation'])
365
+ return list(a.union(b))
364
366
 
365
367
  def _get_annotations_internal(
366
368
  self,
367
- annotations: list[Annotation],
369
+ annotations: Sequence[Annotation],
368
370
  type: Literal['label', 'category', 'segmentation', 'all'] = 'all',
369
371
  scope: Literal['frame', 'image', 'all'] = 'all'
370
372
  ) -> list[Annotation]:
@@ -441,10 +443,8 @@ class DatamintBaseDataset:
441
443
 
442
444
  def get_resources_ids(self) -> list[str]:
443
445
  """Get list of resource IDs."""
444
- return [
445
- self.__getitem_internal(i, only_load_metainfo=True)['metainfo']['id']
446
- for i in self.subset_indices
447
- ]
446
+ return [self._get_image_metainfo(i, bypass_subset_indices=True)['metainfo']['id']
447
+ for i in self.subset_indices]
448
448
 
449
449
  def _get_labels_set(self, framed: bool) -> tuple[dict, dict[str, dict[str, int]]]:
450
450
  """Returns the set of labels and mappings to integers.
@@ -992,7 +992,6 @@ class DatamintBaseDataset:
992
992
  return Path(resource['file'])
993
993
  else:
994
994
  # ext = guess_extension(resource['mimetype'])
995
- # _LOGGER.debug(f"Guessed extension for resource {resource['id']}|{resource['mimetype']}: {ext}")
996
995
  # if ext is None:
997
996
  # _LOGGER.warning(f"Could not guess extension for resource {resource['id']}.")
998
997
  # ext = ''
@@ -1,5 +1,5 @@
1
1
  from .base_dataset import DatamintBaseDataset
2
- from typing import List, Optional, Callable, Any, Dict, Literal
2
+ from typing import List, Optional, Callable, Any, Dict, Literal, Sequence
3
3
  import torch
4
4
  from torch import Tensor
5
5
  import os
@@ -8,6 +8,7 @@ import logging
8
8
  from PIL import Image
9
9
  import albumentations
10
10
  from datamint.entities.annotation import Annotation
11
+ from medimgkit.readers import read_array_normalized
11
12
 
12
13
  _LOGGER = logging.getLogger(__name__)
13
14
 
@@ -117,7 +118,9 @@ class DatamintDataset(DatamintBaseDataset):
117
118
  if semantic_seg_merge_strategy is not None and not return_as_semantic_segmentation:
118
119
  raise ValueError("semantic_seg_merge_strategy can only be used if return_as_semantic_segmentation is True")
119
120
 
120
- def _load_segmentations(self, annotations: list[Annotation], img_shape) -> tuple[dict[str, list], dict[str, list]]:
121
+ def _load_segmentations(self,
122
+ annotations: list[Annotation],
123
+ img_shape) -> tuple[dict[str, list], dict[str, list]]:
121
124
  """
122
125
  Load segmentations from annotations.
123
126
 
@@ -152,19 +155,27 @@ class DatamintDataset(DatamintBaseDataset):
152
155
 
153
156
  segfilepath = ann.file # png file
154
157
  segfilepath = os.path.join(self.dataset_dir, segfilepath)
155
- # FIXME: avoid enforcing resizing the mask
156
- seg = (Image.open(segfilepath)
157
- .convert('L')
158
- .resize((w, h), Image.Resampling.NEAREST)
159
- )
160
- seg = np.array(seg)
158
+ seg = read_array_normalized(segfilepath) # (frames, C, H, W)
159
+ if seg.shape[1] != 1:
160
+ raise ValueError(f"Segmentation file must have 1 channel, got {seg.shape} in {segfilepath}")
161
+ seg = seg[:, 0, :, :] # (frames, H, W)
162
+
163
+ # # FIXME: avoid enforcing resizing the mask
164
+ # seg = (Image.open(segfilepath)
165
+ # .convert('L')
166
+ # .resize((w, h), Image.Resampling.NEAREST)
167
+ # )
168
+ # seg = np.array(seg)
161
169
 
162
170
  seg = torch.from_numpy(seg)
163
171
  seg = seg == 255 # binary mask
164
172
  # map the segmentation label to the code
165
- seg_code = self.frame_lcodes['segmentation'][ann.name]
166
173
  if self.return_frame_by_frame:
167
174
  frame_index = 0
175
+ if seg.shape[0] != 1:
176
+ raise NotImplementedError(
177
+ "Volume segmentations are not supported yet when return_frame_by_frame is True")
178
+ seg = seg[0:1] # (#frames, H, W) -> (1, H, W)
168
179
  else:
169
180
  frame_index = ann.index
170
181
 
@@ -174,12 +185,25 @@ class DatamintDataset(DatamintBaseDataset):
174
185
  author_segs = segmentations[author]
175
186
  author_labels = seg_labels[author]
176
187
 
177
- if author_segs[frame_index] is None:
178
- author_segs[frame_index] = []
179
- author_labels[frame_index] = []
180
-
181
- author_segs[frame_index].append(seg)
182
- author_labels[frame_index].append(seg_code)
188
+ if frame_index is not None and ann.scope == 'frame':
189
+ seg_code = self.frame_lcodes['segmentation'][ann.name]
190
+ if author_segs[frame_index] is None:
191
+ author_segs[frame_index] = []
192
+ author_labels[frame_index] = []
193
+ s = seg[0] if seg.shape[0] == 1 else seg[frame_index]
194
+ author_segs[frame_index].append(s)
195
+ author_labels[frame_index].append(seg_code)
196
+ elif frame_index is None and ann.scope == 'image':
197
+ seg_code = self.image_lcodes['segmentation'][ann.name]
198
+ # apply to all frames
199
+ for i in range(nframes):
200
+ if author_segs[i] is None:
201
+ author_segs[i] = []
202
+ author_labels[i] = []
203
+ author_segs[i].append(seg[i])
204
+ author_labels[i].append(seg_code)
205
+ else:
206
+ raise ValueError(f"Invalid segmentation annotation: {ann}")
183
207
 
184
208
  # convert to tensor
185
209
  for author in segmentations.keys():
@@ -196,8 +220,8 @@ class DatamintDataset(DatamintBaseDataset):
196
220
  return segmentations, seg_labels
197
221
 
198
222
  def _instanceseg2semanticseg(self,
199
- segmentations: List[Tensor],
200
- seg_labels: List[Tensor]) -> Tensor:
223
+ segmentations: Sequence[Tensor],
224
+ seg_labels: Sequence[Tensor]) -> Tensor:
201
225
  """
202
226
  Convert instance segmentation to semantic segmentation.
203
227
 
@@ -208,25 +232,26 @@ class DatamintDataset(DatamintBaseDataset):
208
232
  Returns:
209
233
  Tensor: tensor of shape (n, num_labels, H, W), where `n` is the number of frames.
210
234
  """
211
- if segmentations is not None:
212
- if len(segmentations) != len(seg_labels):
213
- raise ValueError("segmentations and seg_labels must have the same length")
214
-
215
- h, w = segmentations[0].shape[1:]
216
- new_shape = (len(segmentations),
217
- len(self.segmentation_labels_set)+1, # +1 for background
218
- h, w)
219
- new_segmentations = torch.zeros(new_shape, dtype=torch.uint8)
220
- # for each frame
221
- for i in range(len(segmentations)):
222
- # for each instance
223
- for j in range(len(segmentations[i])):
224
- new_segmentations[i, seg_labels[i][j]] += segmentations[i][j]
225
- new_segmentations = new_segmentations > 0
226
- # pixels that are not in any segmentation are labeled as background
227
- new_segmentations[:, 0] = new_segmentations.sum(dim=1) == 0
228
- segmentations = new_segmentations.float()
229
- return segmentations
235
+ if segmentations is None:
236
+ return None
237
+
238
+ if len(segmentations) != len(seg_labels):
239
+ raise ValueError("segmentations and seg_labels must have the same length")
240
+
241
+ h, w = segmentations[0].shape[1:]
242
+ new_shape = (len(segmentations),
243
+ len(self.segmentation_labels_set)+1, # +1 for background
244
+ h, w)
245
+ new_segmentations = torch.zeros(new_shape, dtype=torch.uint8)
246
+ # for each frame
247
+ for i in range(len(segmentations)):
248
+ # for each instance
249
+ for j in range(len(segmentations[i])):
250
+ new_segmentations[i, seg_labels[i][j]] += segmentations[i][j]
251
+ new_segmentations = new_segmentations > 0
252
+ # pixels that are not in any segmentation are labeled as background
253
+ new_segmentations[:, 0] = new_segmentations.sum(dim=1) == 0
254
+ return new_segmentations.float()
230
255
 
231
256
  def apply_semantic_seg_merge_strategy(self, segmentations: dict[str, Tensor],
232
257
  nframes: int,
@@ -338,7 +363,7 @@ class DatamintDataset(DatamintBaseDataset):
338
363
  if isinstance(labels, Tensor):
339
364
  # single tensor for the author
340
365
  seg_names[author] = [code_to_name[code.item()-1] for code in labels]
341
- elif isinstance(labels, list):
366
+ elif isinstance(labels, Sequence):
342
367
  # list of frame tensors
343
368
  seg_names[author] = [[code_to_name[code.item()-1] for code in frame_labels]
344
369
  for frame_labels in labels]
@@ -477,7 +502,7 @@ class DatamintDataset(DatamintBaseDataset):
477
502
  return new_item
478
503
 
479
504
  def _convert_labels_annotations(self,
480
- annotations: list[Annotation],
505
+ annotations: Sequence[Annotation],
481
506
  num_frames: int | None = None) -> dict[str, torch.Tensor]:
482
507
  """
483
508
  Converts the annotations, of the same type and scope, to tensor of shape (num_frames, num_labels)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datamint
3
- Version: 2.1.0
3
+ Version: 2.1.2
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
@@ -21,7 +21,7 @@ Requires-Dist: humanize (>=4.0.0,<5.0.0)
21
21
  Requires-Dist: lazy-loader (>=0.3.0)
22
22
  Requires-Dist: lightning
23
23
  Requires-Dist: matplotlib
24
- Requires-Dist: medimgkit (>=0.6.2)
24
+ Requires-Dist: medimgkit (>=0.6.4)
25
25
  Requires-Dist: nest-asyncio (>=1.0.0,<2.0.0)
26
26
  Requires-Dist: nibabel (>=4.0.0)
27
27
  Requires-Dist: numpy
@@ -1,6 +1,6 @@
1
1
  datamint/__init__.py,sha256=ucsnxrYClh6pdy7psRJXWam_9rjAQB4NXzvy7xLovmo,824
2
2
  datamint/api/__init__.py,sha256=7QYkmDBXbKh8-zchV7k6Lpolaw6h-IK6ezfXROIWh2A,43
3
- datamint/api/base_api.py,sha256=MIq1sQA4mD9_SWxAEDjxtxm3Q-tj6kZ05KRnNoLPM7E,16576
3
+ datamint/api/base_api.py,sha256=Iu9oJEZ8YlIF5xcbH_M0Lkb7t9ZDNFLzjJp9bPDHW1c,16628
4
4
  datamint/api/client.py,sha256=1XTZUlbAISe0jwug1rrANgWJToXxYeXx8_HD-ZWJurU,3354
5
5
  datamint/api/dto/__init__.py,sha256=KOSNl1axDDE5eBt68MmsgkyE0Ds_1DDzWUg73iyoWvc,281
6
6
  datamint/api/endpoints/__init__.py,sha256=S46nVAlXgGe8wNcBEhW8ffGJjGNAmhhRTDTsvG9fWBE,402
@@ -24,8 +24,8 @@ datamint/client_cmd_tools/datamint_upload.py,sha256=jPzvlNeBZfOOxuG6ryswJ8OG4jXu
24
24
  datamint/configs.py,sha256=Bdp6NydYwyCJ2dk19_gf_o3M2ZyQOmMHpLi8wEWNHUk,1426
25
25
  datamint/dataset/__init__.py,sha256=4PlUKSvVhdfQvvuq8jQXrkdqnot-iTTizM3aM1vgSwg,47
26
26
  datamint/dataset/annotation.py,sha256=qN1IMjdfLD2ceQ6va3l76jOXA8Vb_c-eBk1oWQu6hW0,7994
27
- datamint/dataset/base_dataset.py,sha256=Ai_fEMW1lmA9ZxGc_7Zuz3zjVUsbzpbnWeDMy7eZLVQ,49583
28
- datamint/dataset/dataset.py,sha256=It-HOTi83ls4ww2qCAvFYU0_OLLrFclj0QQapMYgDAE,27333
27
+ datamint/dataset/base_dataset.py,sha256=xdWnYNZ6yKi__YGkrJ3hssiljRV3InGlJn8zDcgJnp8,49547
28
+ datamint/dataset/dataset.py,sha256=huUOyBRGVtcx0tcpX2FrsWn7Vsqy5i5e_J52gxR_29A,28637
29
29
  datamint/entities/__init__.py,sha256=tbHE7rZb0R9Hm-Dc8VWEq3PlRl7BYOzffumrV0ZdsMs,444
30
30
  datamint/entities/annotation.py,sha256=ochAEh_JqxAe_FyYTNUfPT47KiIAG7CkBTim52bu7M8,6636
31
31
  datamint/entities/base_entity.py,sha256=DniakCgJ-gV7Hz8VKQA_dRYTp4DU5rcjLBVOuD1aZuA,1902
@@ -44,7 +44,7 @@ datamint/logging.yaml,sha256=tOMxtc2UmwlIMTK6ljtnBwTco1PNrPeq3mx2iMuSbiw,482
44
44
  datamint/utils/logging_utils.py,sha256=9pRoaPrWu2jOdDCiAoUsjEdP5ZwaealWL3hjUqFvx9g,4022
45
45
  datamint/utils/torchmetrics.py,sha256=lwU0nOtsSWfebyp7dvjlAggaqXtj5ohSEUXOg3L0hJE,2837
46
46
  datamint/utils/visualization.py,sha256=yaUVAOHar59VrGUjpAWv5eVvQSfztFG0eP9p5Vt3l-M,4470
47
- datamint-2.1.0.dist-info/METADATA,sha256=JFlip7Zr_9y7MzxTz4NUw3vNbDQtAI8rOtiSRtqPbwM,4203
48
- datamint-2.1.0.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
49
- datamint-2.1.0.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
50
- datamint-2.1.0.dist-info/RECORD,,
47
+ datamint-2.1.2.dist-info/METADATA,sha256=K-uz7hcmvpOky8LA-r1hkOBMsXyRW1us9qT8F63mn6s,4203
48
+ datamint-2.1.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
49
+ datamint-2.1.2.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
50
+ datamint-2.1.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any