deepdoctection 0.30__py3-none-any.whl → 0.32__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 deepdoctection might be problematic. Click here for more details.

Files changed (120) hide show
  1. deepdoctection/__init__.py +38 -29
  2. deepdoctection/analyzer/dd.py +36 -29
  3. deepdoctection/configs/conf_dd_one.yaml +34 -31
  4. deepdoctection/dataflow/base.py +0 -19
  5. deepdoctection/dataflow/custom.py +4 -3
  6. deepdoctection/dataflow/custom_serialize.py +14 -5
  7. deepdoctection/dataflow/parallel_map.py +12 -11
  8. deepdoctection/dataflow/serialize.py +5 -4
  9. deepdoctection/datapoint/annotation.py +35 -13
  10. deepdoctection/datapoint/box.py +3 -5
  11. deepdoctection/datapoint/convert.py +3 -1
  12. deepdoctection/datapoint/image.py +79 -36
  13. deepdoctection/datapoint/view.py +152 -49
  14. deepdoctection/datasets/__init__.py +1 -4
  15. deepdoctection/datasets/adapter.py +6 -3
  16. deepdoctection/datasets/base.py +86 -11
  17. deepdoctection/datasets/dataflow_builder.py +1 -1
  18. deepdoctection/datasets/info.py +4 -4
  19. deepdoctection/datasets/instances/doclaynet.py +3 -2
  20. deepdoctection/datasets/instances/fintabnet.py +2 -1
  21. deepdoctection/datasets/instances/funsd.py +2 -1
  22. deepdoctection/datasets/instances/iiitar13k.py +5 -2
  23. deepdoctection/datasets/instances/layouttest.py +4 -8
  24. deepdoctection/datasets/instances/publaynet.py +2 -2
  25. deepdoctection/datasets/instances/pubtables1m.py +6 -3
  26. deepdoctection/datasets/instances/pubtabnet.py +2 -1
  27. deepdoctection/datasets/instances/rvlcdip.py +2 -1
  28. deepdoctection/datasets/instances/xfund.py +2 -1
  29. deepdoctection/eval/__init__.py +1 -4
  30. deepdoctection/eval/accmetric.py +1 -1
  31. deepdoctection/eval/base.py +5 -4
  32. deepdoctection/eval/cocometric.py +2 -1
  33. deepdoctection/eval/eval.py +19 -15
  34. deepdoctection/eval/tedsmetric.py +14 -11
  35. deepdoctection/eval/tp_eval_callback.py +14 -7
  36. deepdoctection/extern/__init__.py +2 -7
  37. deepdoctection/extern/base.py +39 -13
  38. deepdoctection/extern/d2detect.py +182 -90
  39. deepdoctection/extern/deskew.py +36 -9
  40. deepdoctection/extern/doctrocr.py +265 -83
  41. deepdoctection/extern/fastlang.py +49 -9
  42. deepdoctection/extern/hfdetr.py +106 -55
  43. deepdoctection/extern/hflayoutlm.py +441 -122
  44. deepdoctection/extern/hflm.py +225 -0
  45. deepdoctection/extern/model.py +56 -47
  46. deepdoctection/extern/pdftext.py +10 -5
  47. deepdoctection/extern/pt/__init__.py +1 -3
  48. deepdoctection/extern/pt/nms.py +6 -2
  49. deepdoctection/extern/pt/ptutils.py +27 -18
  50. deepdoctection/extern/tessocr.py +134 -22
  51. deepdoctection/extern/texocr.py +6 -2
  52. deepdoctection/extern/tp/tfutils.py +43 -9
  53. deepdoctection/extern/tp/tpcompat.py +14 -11
  54. deepdoctection/extern/tp/tpfrcnn/__init__.py +20 -0
  55. deepdoctection/extern/tp/tpfrcnn/common.py +7 -3
  56. deepdoctection/extern/tp/tpfrcnn/config/__init__.py +20 -0
  57. deepdoctection/extern/tp/tpfrcnn/config/config.py +9 -6
  58. deepdoctection/extern/tp/tpfrcnn/modeling/__init__.py +20 -0
  59. deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +17 -7
  60. deepdoctection/extern/tp/tpfrcnn/modeling/generalized_rcnn.py +12 -6
  61. deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +9 -4
  62. deepdoctection/extern/tp/tpfrcnn/modeling/model_cascade.py +8 -5
  63. deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +16 -11
  64. deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +17 -10
  65. deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +14 -8
  66. deepdoctection/extern/tp/tpfrcnn/modeling/model_rpn.py +15 -10
  67. deepdoctection/extern/tp/tpfrcnn/predict.py +9 -4
  68. deepdoctection/extern/tp/tpfrcnn/preproc.py +8 -9
  69. deepdoctection/extern/tp/tpfrcnn/utils/__init__.py +20 -0
  70. deepdoctection/extern/tp/tpfrcnn/utils/box_ops.py +10 -2
  71. deepdoctection/extern/tpdetect.py +54 -30
  72. deepdoctection/mapper/__init__.py +3 -8
  73. deepdoctection/mapper/d2struct.py +9 -7
  74. deepdoctection/mapper/hfstruct.py +7 -2
  75. deepdoctection/mapper/laylmstruct.py +164 -21
  76. deepdoctection/mapper/maputils.py +16 -3
  77. deepdoctection/mapper/misc.py +6 -3
  78. deepdoctection/mapper/prodigystruct.py +1 -1
  79. deepdoctection/mapper/pubstruct.py +10 -10
  80. deepdoctection/mapper/tpstruct.py +3 -3
  81. deepdoctection/pipe/__init__.py +1 -1
  82. deepdoctection/pipe/anngen.py +35 -8
  83. deepdoctection/pipe/base.py +53 -19
  84. deepdoctection/pipe/common.py +23 -13
  85. deepdoctection/pipe/concurrency.py +2 -1
  86. deepdoctection/pipe/doctectionpipe.py +2 -2
  87. deepdoctection/pipe/language.py +3 -2
  88. deepdoctection/pipe/layout.py +6 -3
  89. deepdoctection/pipe/lm.py +34 -66
  90. deepdoctection/pipe/order.py +142 -35
  91. deepdoctection/pipe/refine.py +26 -24
  92. deepdoctection/pipe/segment.py +21 -16
  93. deepdoctection/pipe/{cell.py → sub_layout.py} +30 -9
  94. deepdoctection/pipe/text.py +14 -8
  95. deepdoctection/pipe/transform.py +16 -9
  96. deepdoctection/train/__init__.py +6 -12
  97. deepdoctection/train/d2_frcnn_train.py +36 -28
  98. deepdoctection/train/hf_detr_train.py +26 -17
  99. deepdoctection/train/hf_layoutlm_train.py +133 -111
  100. deepdoctection/train/tp_frcnn_train.py +21 -19
  101. deepdoctection/utils/__init__.py +3 -0
  102. deepdoctection/utils/concurrency.py +1 -1
  103. deepdoctection/utils/context.py +2 -2
  104. deepdoctection/utils/env_info.py +41 -84
  105. deepdoctection/utils/error.py +84 -0
  106. deepdoctection/utils/file_utils.py +4 -15
  107. deepdoctection/utils/fs.py +7 -7
  108. deepdoctection/utils/logger.py +1 -0
  109. deepdoctection/utils/mocks.py +93 -0
  110. deepdoctection/utils/pdf_utils.py +5 -4
  111. deepdoctection/utils/settings.py +6 -1
  112. deepdoctection/utils/transform.py +1 -1
  113. deepdoctection/utils/utils.py +0 -6
  114. deepdoctection/utils/viz.py +48 -5
  115. {deepdoctection-0.30.dist-info → deepdoctection-0.32.dist-info}/METADATA +57 -73
  116. deepdoctection-0.32.dist-info/RECORD +146 -0
  117. {deepdoctection-0.30.dist-info → deepdoctection-0.32.dist-info}/WHEEL +1 -1
  118. deepdoctection-0.30.dist-info/RECORD +0 -143
  119. {deepdoctection-0.30.dist-info → deepdoctection-0.32.dist-info}/LICENSE +0 -0
  120. {deepdoctection-0.30.dist-info → deepdoctection-0.32.dist-info}/top_level.txt +0 -0
@@ -24,6 +24,7 @@ from dataclasses import dataclass, field
24
24
  from typing import Any, Dict, List, Optional, Union, no_type_check
25
25
 
26
26
  from ..utils.detection_types import JsonDict
27
+ from ..utils.error import AnnotationError, UUIDError
27
28
  from ..utils.identifier import get_uuid, is_uuid_like
28
29
  from ..utils.logger import LoggingRecord, logger
29
30
  from ..utils.settings import DefaultType, ObjectTypes, SummaryType, TypeOrStr, get_type
@@ -36,7 +37,16 @@ def ann_from_dict(cls, **kwargs):
36
37
  """
37
38
  A factory function to create subclasses of annotations from a given dict
38
39
  """
39
- ann = cls(kwargs.get("external_id"), kwargs.get("category_name"), kwargs.get("category_id"), kwargs.get("score"))
40
+ _init_kwargs = {
41
+ "external_id": kwargs.get("external_id"),
42
+ "category_name": kwargs.get("category_name"),
43
+ "category_id": kwargs.get("category_id"),
44
+ "score": kwargs.get("score"),
45
+ "service_id": kwargs.get("service_id"),
46
+ "model_id": kwargs.get("model_id"),
47
+ "session_id": kwargs.get("session_id"),
48
+ }
49
+ ann = cls(**_init_kwargs)
40
50
  ann.active = kwargs.get("active")
41
51
  ann._annotation_id = kwargs.get("_annotation_id") # pylint: disable=W0212
42
52
  if isinstance(kwargs.get("sub_categories"), dict):
@@ -74,11 +84,17 @@ class Annotation(ABC):
74
84
  id will not depend on the defining attributes.
75
85
 
76
86
  `_annotation_id`: Unique id for annotations. Will always be given as string representation of a md5-hash.
87
+ `service_id`: Service that generated the annotation. This will be the name of a pipeline component
88
+ `model_id`: Model that generated the annotation. This will be the name of particular model
89
+ `session_id`: Session id for the annotation. This will be the id of the session in which the annotation was created.
77
90
  """
78
91
 
79
92
  active: bool = field(default=True, init=False, repr=True)
80
93
  external_id: Optional[Union[str, int]] = field(default=None, init=True, repr=False)
81
94
  _annotation_id: Optional[str] = field(default=None, init=False, repr=True)
95
+ service_id: Optional[str] = field(default=None)
96
+ model_id: Optional[str] = field(default=None)
97
+ session_id: Optional[str] = field(default=None)
82
98
 
83
99
  def __post_init__(self) -> None:
84
100
  """
@@ -101,7 +117,7 @@ class Annotation(ABC):
101
117
  """
102
118
  if self._annotation_id:
103
119
  return self._annotation_id
104
- raise ValueError("Dump annotation first or pass external_id to create an annotation id")
120
+ raise AnnotationError("Dump annotation first or pass external_id to create an annotation id")
105
121
 
106
122
  @annotation_id.setter
107
123
  def annotation_id(self, input_id: str) -> None:
@@ -109,13 +125,13 @@ class Annotation(ABC):
109
125
  annotation_id setter
110
126
  """
111
127
  if self._annotation_id is not None:
112
- raise AssertionError("Annotation_id already defined and cannot be reset")
128
+ raise AnnotationError("Annotation_id already defined and cannot be reset")
113
129
  if is_uuid_like(input_id):
114
130
  self._annotation_id = input_id
115
131
  elif isinstance(input_id, property):
116
132
  pass
117
133
  else:
118
- raise ValueError("Annotation_id must be uuid3 string")
134
+ raise AnnotationError("Annotation_id must be uuid3 string")
119
135
 
120
136
  @abstractmethod
121
137
  def get_defining_attributes(self) -> List[str]:
@@ -126,13 +142,13 @@ class Annotation(ABC):
126
142
 
127
143
  :return: A list of attributes.
128
144
  """
129
- raise NotImplementedError
145
+ raise NotImplementedError()
130
146
 
131
147
  def _assert_attributes_have_str(self, state_id: bool = False) -> None:
132
148
  defining_attributes = self.get_state_attributes() if state_id else self.get_defining_attributes()
133
149
  for attr in defining_attributes:
134
150
  if not hasattr(eval("self." + attr), "__str__"): # pylint: disable=W0123
135
- raise AttributeError(f"Attribute {attr} must have __str__ method")
151
+ raise AnnotationError(f"Attribute {attr} must have __str__ method")
136
152
 
137
153
  @staticmethod
138
154
  def set_annotation_id(annotation: "CategoryAnnotation", *container_id_context: Optional[str]) -> str:
@@ -179,7 +195,7 @@ class Annotation(ABC):
179
195
 
180
196
  :return: Annotation instance
181
197
  """
182
- raise NotImplementedError
198
+ raise NotImplementedError()
183
199
 
184
200
  @staticmethod
185
201
  @abstractmethod
@@ -189,7 +205,7 @@ class Annotation(ABC):
189
205
 
190
206
  :return: A list of attributes.
191
207
  """
192
- raise NotImplementedError
208
+ raise NotImplementedError()
193
209
 
194
210
  @property
195
211
  def state_id(self) -> str:
@@ -290,7 +306,12 @@ class CategoryAnnotation(Annotation):
290
306
  """
291
307
 
292
308
  if sub_category_name in self.sub_categories:
293
- raise KeyError(f"{sub_category_name} as sub category already defined for " f"{self.annotation_id}")
309
+ raise AnnotationError(
310
+ f"sub category {sub_category_name} already defined: "
311
+ f"annotation_id: {self.annotation_id}, "
312
+ f"category_name: {self.category_name}, "
313
+ f"category_id: {self.category_id}"
314
+ )
294
315
 
295
316
  if self._annotation_id is not None:
296
317
  if annotation._annotation_id is None: # pylint: disable=W0212
@@ -333,7 +354,7 @@ class CategoryAnnotation(Annotation):
333
354
  :param annotation_id: An annotation id
334
355
  """
335
356
  if not is_uuid_like(annotation_id):
336
- raise ValueError("Annotation_id must be uuid")
357
+ raise UUIDError("Annotation_id must be uuid")
337
358
 
338
359
  key_type = get_type(key)
339
360
  if key not in self.relationships:
@@ -436,14 +457,14 @@ class ImageAnnotation(CategoryAnnotation):
436
457
  box = self.bounding_box
437
458
  if box:
438
459
  return box
439
- raise ValueError(f"bounding_box has not been initialized for {self.annotation_id}")
460
+ raise AnnotationError(f"bounding_box has not been initialized for {self.annotation_id}")
440
461
 
441
462
  def get_summary(self, key: ObjectTypes) -> CategoryAnnotation:
442
463
  """Get summary sub categories from `image`. Raises `ValueError` if `key` is not available"""
443
464
  if self.image:
444
465
  if self.image.summary:
445
466
  return self.image.summary.get_sub_category(key)
446
- raise ValueError(f"Summary does not exist for {self.annotation_id} and key: {key}")
467
+ raise AnnotationError(f"Summary does not exist for {self.annotation_id} and key: {key}")
447
468
 
448
469
 
449
470
  @dataclass
@@ -483,5 +504,6 @@ class ContainerAnnotation(CategoryAnnotation):
483
504
  @classmethod
484
505
  def from_dict(cls, **kwargs: JsonDict) -> "SummaryAnnotation":
485
506
  container_ann = ann_from_dict(cls, **kwargs)
486
- container_ann.value = kwargs.get("value")
507
+ value = kwargs.get("value", "")
508
+ container_ann.value = value if isinstance(value, str) else list(value)
487
509
  return container_ann
@@ -25,13 +25,15 @@ from typing import List, Optional, Sequence, no_type_check
25
25
 
26
26
  import numpy as np
27
27
  import numpy.typing as npt
28
+ from lazy_imports import try_import
28
29
  from numpy import float32
29
30
 
30
31
  from ..utils.detection_types import ImageType
32
+ from ..utils.error import BoundingBoxError
31
33
  from ..utils.file_utils import cocotools_available
32
34
  from ..utils.logger import LoggingRecord, logger
33
35
 
34
- if cocotools_available():
36
+ with try_import() as import_guard:
35
37
  import pycocotools.mask as coco_mask
36
38
 
37
39
 
@@ -140,10 +142,6 @@ def iou(boxes1: npt.NDArray[float32], boxes2: npt.NDArray[float32]) -> npt.NDArr
140
142
  return np_iou(boxes1, boxes2)
141
143
 
142
144
 
143
- class BoundingBoxError(BaseException):
144
- """Special exception only for `BoundingBox`"""
145
-
146
-
147
145
  @dataclass
148
146
  class BoundingBox:
149
147
  """
@@ -32,6 +32,7 @@ from pypdf import PdfReader
32
32
 
33
33
  from ..utils.detection_types import ImageType
34
34
  from ..utils.develop import deprecated
35
+ from ..utils.error import DependencyError
35
36
  from ..utils.pdf_utils import pdf_to_np_array
36
37
  from ..utils.viz import viz_handler
37
38
 
@@ -121,7 +122,8 @@ def convert_pdf_bytes_to_np_array(pdf_bytes: bytes, dpi: Optional[int] = None) -
121
122
  """
122
123
  from pdf2image import convert_from_bytes # type: ignore # pylint: disable=C0415, E0401
123
124
 
124
- assert which("pdftoppm") is not None, "convert_pdf_bytes_to_np_array requires poppler to be installed"
125
+ if which("pdftoppm") is None:
126
+ raise DependencyError("convert_pdf_bytes_to_np_array requires poppler to be installed")
125
127
 
126
128
  with BytesIO(pdf_bytes) as pdf_file:
127
129
  pdf = PdfReader(pdf_file).pages[0]
@@ -18,6 +18,8 @@
18
18
  """
19
19
  Dataclass Image
20
20
  """
21
+ from __future__ import annotations
22
+
21
23
  import json
22
24
  from dataclasses import dataclass, field
23
25
  from os import environ
@@ -28,6 +30,7 @@ import numpy as np
28
30
  from numpy import uint8
29
31
 
30
32
  from ..utils.detection_types import ImageType, JsonDict, Pathlike
33
+ from ..utils.error import AnnotationError, BoundingBoxError, ImageError, UUIDError
31
34
  from ..utils.identifier import get_uuid, is_uuid_like
32
35
  from ..utils.settings import ObjectTypes, get_type
33
36
  from .annotation import Annotation, BoundingBox, ImageAnnotation, SummaryAnnotation
@@ -108,7 +111,7 @@ class Image:
108
111
  """
109
112
  if self._image_id is not None:
110
113
  return self._image_id
111
- raise ValueError("image_id not set")
114
+ raise ImageError("image_id not set")
112
115
 
113
116
  @image_id.setter
114
117
  def image_id(self, input_id: str) -> None:
@@ -116,13 +119,13 @@ class Image:
116
119
  image_id setter
117
120
  """
118
121
  if self._image_id is not None:
119
- raise ValueError("image_id already defined and cannot be reset")
122
+ raise ImageError("image_id already defined and cannot be reset")
120
123
  if is_uuid_like(input_id):
121
124
  self._image_id = input_id
122
125
  elif isinstance(input_id, property):
123
126
  pass
124
127
  else:
125
- raise ValueError("image_id must be uuid3 string")
128
+ raise UUIDError("image_id must be uuid3 string")
126
129
 
127
130
  @property
128
131
  def image(self) -> Optional[ImageType]:
@@ -153,7 +156,7 @@ class Image:
153
156
  self._self_embedding()
154
157
  else:
155
158
  if not isinstance(image, np.ndarray):
156
- raise TypeError(f"Cannot load image is of type: {type(image)}")
159
+ raise ImageError(f"Cannot load image is of type: {type(image)}")
157
160
  self._image = image.astype(uint8)
158
161
  self.set_width_height(self._image.shape[1], self._image.shape[0])
159
162
  self._self_embedding()
@@ -201,7 +204,7 @@ class Image:
201
204
  self._bbox = None
202
205
  self.embeddings.pop(self.image_id)
203
206
 
204
- def get_image(self) -> "_Img": # type: ignore
207
+ def get_image(self) -> _Img: # type: ignore # pylint: disable=E0602
205
208
  """
206
209
  Get the image either in base64 string representation or as np.array.
207
210
 
@@ -248,7 +251,7 @@ class Image:
248
251
  width
249
252
  """
250
253
  if self._bbox is None:
251
- raise ValueError("Width not available. Call set_width_height first")
254
+ raise ImageError("Width not available. Call set_width_height first")
252
255
  return self._bbox.width
253
256
 
254
257
  @property
@@ -257,7 +260,7 @@ class Image:
257
260
  height
258
261
  """
259
262
  if self._bbox is None:
260
- raise ValueError("Height not available. Call set_width_height first")
263
+ raise ImageError("Height not available. Call set_width_height first")
261
264
  return self._bbox.height
262
265
 
263
266
  def set_width_height(self, width: float, height: float) -> None:
@@ -281,7 +284,7 @@ class Image:
281
284
  :param bounding_box: bounding box of this image in terms of the embedding image.
282
285
  """
283
286
  if not isinstance(bounding_box, BoundingBox):
284
- raise TypeError(f"Bounding box must be of type BoundingBox, is of type {type(bounding_box)}")
287
+ raise BoundingBoxError(f"Bounding box must be of type BoundingBox, is of type {type(bounding_box)}")
285
288
  self.embeddings[image_id] = bounding_box
286
289
 
287
290
  def get_embedding(self, image_id: str) -> BoundingBox:
@@ -307,14 +310,14 @@ class Image:
307
310
  :param annotation: image annotation to store
308
311
  """
309
312
  if not isinstance(annotation, ImageAnnotation):
310
- raise TypeError(
313
+ raise AnnotationError(
311
314
  f"Annotation must be of type ImageAnnotation: "
312
315
  f"{annotation.annotation_id} but is of type {str(type(annotation))}"
313
316
  )
314
317
  if annotation._annotation_id is None: # pylint: disable=W0212
315
318
  annotation.annotation_id = self.define_annotation_id(annotation)
316
319
  if annotation.annotation_id in self._annotation_ids:
317
- raise ValueError(f"Cannot dump annotation with already taken " f"id {annotation.annotation_id}")
320
+ raise ImageError(f"Cannot dump annotation with already taken " f"id {annotation.annotation_id}")
318
321
  self._annotation_ids.append(annotation.annotation_id)
319
322
  self.annotations.append(annotation)
320
323
 
@@ -322,7 +325,10 @@ class Image:
322
325
  self,
323
326
  category_names: Optional[Union[str, ObjectTypes, Sequence[Union[str, ObjectTypes]]]] = None,
324
327
  annotation_ids: Optional[Union[str, Sequence[str]]] = None,
325
- annotation_types: Optional[Union[str, Sequence[str]]] = None,
328
+ service_id: Optional[Union[str, Sequence[str]]] = None,
329
+ model_id: Optional[Union[str, Sequence[str]]] = None,
330
+ session_ids: Optional[Union[str, Sequence[str]]] = None,
331
+ ignore_inactive: bool = True,
326
332
  ) -> List[ImageAnnotation]:
327
333
  """
328
334
  Selection of annotations from the annotation container. Filter conditions can be defined by specifying
@@ -333,47 +339,80 @@ class Image:
333
339
 
334
340
  :param category_names: A single name or list of names
335
341
  :param annotation_ids: A single id or list of ids
336
- :param annotation_types: A type name or list of type names.
342
+ :param service_id: A single service name or list of service names
343
+ :param model_id: A single model name or list of model names
344
+ :param session_ids: A single session id or list of session ids
345
+ :param ignore_inactive: If set to `True` only active annotations are returned.
346
+
337
347
  :return: A (possibly empty) list of Annotations
338
348
  """
339
349
 
340
- cat_names = [category_names] if isinstance(category_names, (ObjectTypes, str)) else category_names
341
- if cat_names is not None:
342
- cat_names = [get_type(cat_name) for cat_name in cat_names]
343
- ann_ids = [annotation_ids] if isinstance(annotation_ids, str) else annotation_ids
344
- ann_types = [annotation_types] if isinstance(annotation_types, str) else annotation_types
350
+ if category_names is not None:
351
+ category_names = (
352
+ [get_type(cat_name) for cat_name in category_names]
353
+ if isinstance(category_names, (list, set))
354
+ else [get_type(category_names)] # type:ignore
355
+ )
345
356
 
346
- anns = filter(lambda x: x.active, self.annotations)
357
+ ann_ids = [annotation_ids] if isinstance(annotation_ids, str) else annotation_ids
358
+ service_id = [service_id] if isinstance(service_id, str) else service_id
359
+ model_id = [model_id] if isinstance(model_id, str) else model_id
360
+ session_id = [session_ids] if isinstance(session_ids, str) else session_ids
347
361
 
348
- if ann_types is not None:
349
- for type_name in ann_types:
350
- anns = filter(lambda x: isinstance(x, eval(type_name)), anns) # pylint: disable=W0123, W0640
362
+ if ignore_inactive:
363
+ anns = filter(lambda x: x.active, self.annotations)
364
+ else:
365
+ anns = self.annotations # type:ignore
351
366
 
352
- if cat_names is not None:
353
- anns = filter(lambda x: x.category_name in cat_names, anns) # type:ignore
367
+ if category_names is not None:
368
+ anns = filter(lambda x: x.category_name in category_names, anns) # type:ignore
354
369
 
355
370
  if ann_ids is not None:
356
371
  anns = filter(lambda x: x.annotation_id in ann_ids, anns) # type:ignore
357
372
 
373
+ if service_id is not None:
374
+ anns = filter(lambda x: x.service_id in service_id, anns) # type:ignore
375
+
376
+ if model_id is not None:
377
+ anns = filter(lambda x: x.model_id in model_id, anns) # type:ignore
378
+
379
+ if session_id is not None:
380
+ anns = filter(lambda x: x.session_id in session_id, anns) # type:ignore
381
+
358
382
  return list(anns)
359
383
 
360
384
  def get_annotation_iter(
361
385
  self,
362
386
  category_names: Optional[Union[str, ObjectTypes, Sequence[Union[str, ObjectTypes]]]] = None,
363
387
  annotation_ids: Optional[Union[str, Sequence[str]]] = None,
364
- annotation_types: Optional[Union[str, Sequence[str]]] = None,
388
+ service_id: Optional[Union[str, Sequence[str]]] = None,
389
+ model_id: Optional[Union[str, Sequence[str]]] = None,
390
+ session_ids: Optional[Union[str, Sequence[str]]] = None,
391
+ ignore_inactive: bool = True,
365
392
  ) -> Iterable[ImageAnnotation]:
366
393
  """
367
394
  Get annotation as an iterator. Same as `get_annotation` but returns an iterator instead of a list.
368
395
 
369
396
  :param category_names: A single name or list of names
370
397
  :param annotation_ids: A single id or list of ids
371
- :param annotation_types: A type name or list of type names.
398
+ :param service_id: A single service name or list of service names
399
+ :param model_id: A single model name or list of model names
400
+ :param session_ids: A single session id or list of session ids
401
+ :param ignore_inactive: If set to `True` only active annotations are returned.
372
402
 
373
403
  :return: A (possibly empty) list of annotations
374
404
  """
375
405
 
376
- return iter(self.get_annotation(category_names, annotation_ids, annotation_types))
406
+ return iter(
407
+ self.get_annotation(
408
+ category_names=category_names,
409
+ annotation_ids=annotation_ids,
410
+ service_id=service_id,
411
+ model_id=model_id,
412
+ session_ids=session_ids,
413
+ ignore_inactive=ignore_inactive,
414
+ )
415
+ )
377
416
 
378
417
  def as_dict(self) -> Dict[str, Any]:
379
418
  """
@@ -439,7 +478,7 @@ class Image:
439
478
  new_image = Image(file_name=self.file_name, location=self.location, external_id=annotation_id)
440
479
 
441
480
  if self._bbox is None or ann.bounding_box is None:
442
- raise ValueError(f"Bounding box for image and ImageAnnotation ({annotation_id}) must be set")
481
+ raise ImageError(f"Bounding box for image and ImageAnnotation ({annotation_id}) must be set")
443
482
 
444
483
  new_bounding_box = intersection_box(self._bbox, ann.bounding_box, self.width, self.height)
445
484
  if new_bounding_box.absolute_coords:
@@ -454,7 +493,7 @@ class Image:
454
493
  if crop_image and self.image is not None:
455
494
  new_image.image = crop_box_from_image(self.image, ann.bounding_box, self.width, self.height)
456
495
  elif crop_image and self.image is None:
457
- raise ValueError("crop_image = True requires self.image to be not None")
496
+ raise ImageError("crop_image = True requires self.image to be not None")
458
497
 
459
498
  ann.image = new_image
460
499
 
@@ -472,7 +511,7 @@ class Image:
472
511
 
473
512
  ann = self.get_annotation(annotation_ids=annotation_id)[0]
474
513
  if ann.image is None:
475
- raise ValueError("When adding sub images to ImageAnnotation then ImageAnnotation.image must not be None")
514
+ raise ImageError("When adding sub images to ImageAnnotation then ImageAnnotation.image must not be None")
476
515
  assert ann.bounding_box is not None
477
516
  box = ann.bounding_box.to_list("xyxy")
478
517
  proposals = self.get_annotation(category_names)
@@ -485,7 +524,7 @@ class Image:
485
524
  sub_images = self.get_annotation(annotation_ids=selected_ids.tolist())
486
525
  for sub_image in sub_images:
487
526
  if sub_image.image is None:
488
- raise ValueError(
527
+ raise ImageError(
489
528
  "When setting an embedding to ImageAnnotation then ImageAnnotation.image must not be None"
490
529
  )
491
530
  sub_image.image.set_embedding(
@@ -494,16 +533,20 @@ class Image:
494
533
  )
495
534
  ann.image.dump(sub_image)
496
535
 
497
- def remove_image_from_lower_hierachy(self) -> None:
536
+ def remove_image_from_lower_hierachy(self, pixel_values_only: bool = False) -> None:
498
537
  """Will remove all images from image annotations."""
499
538
  for ann in self.annotations:
500
- absolute_bounding_box = ann.get_bounding_box(self.image_id)
501
- ann.bounding_box = absolute_bounding_box
502
- ann.image = None
539
+ if pixel_values_only:
540
+ if ann.image is not None:
541
+ ann.image.clear_image()
542
+ else:
543
+ absolute_bounding_box = ann.get_bounding_box(self.image_id)
544
+ ann.bounding_box = absolute_bounding_box
545
+ ann.image = None
503
546
 
504
547
  @classmethod
505
548
  @no_type_check
506
- def from_dict(cls, **kwargs) -> "Image":
549
+ def from_dict(cls, **kwargs) -> Image:
507
550
  """
508
551
  Create `Image` instance from dict.
509
552
 
@@ -534,7 +577,7 @@ class Image:
534
577
 
535
578
  @classmethod
536
579
  @no_type_check
537
- def from_file(cls, file_path: str) -> "Image":
580
+ def from_file(cls, file_path: str) -> Image:
538
581
  """
539
582
  Create `Image` instance from .json file.
540
583