deepdoctection 0.32__py3-none-any.whl → 0.34__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 (111) hide show
  1. deepdoctection/__init__.py +8 -25
  2. deepdoctection/analyzer/dd.py +84 -71
  3. deepdoctection/dataflow/common.py +9 -5
  4. deepdoctection/dataflow/custom.py +5 -5
  5. deepdoctection/dataflow/custom_serialize.py +75 -18
  6. deepdoctection/dataflow/parallel_map.py +3 -3
  7. deepdoctection/dataflow/serialize.py +4 -4
  8. deepdoctection/dataflow/stats.py +3 -3
  9. deepdoctection/datapoint/annotation.py +78 -56
  10. deepdoctection/datapoint/box.py +7 -7
  11. deepdoctection/datapoint/convert.py +6 -6
  12. deepdoctection/datapoint/image.py +157 -75
  13. deepdoctection/datapoint/view.py +175 -151
  14. deepdoctection/datasets/adapter.py +30 -24
  15. deepdoctection/datasets/base.py +10 -10
  16. deepdoctection/datasets/dataflow_builder.py +3 -3
  17. deepdoctection/datasets/info.py +23 -25
  18. deepdoctection/datasets/instances/doclaynet.py +48 -49
  19. deepdoctection/datasets/instances/fintabnet.py +44 -45
  20. deepdoctection/datasets/instances/funsd.py +23 -23
  21. deepdoctection/datasets/instances/iiitar13k.py +8 -8
  22. deepdoctection/datasets/instances/layouttest.py +2 -2
  23. deepdoctection/datasets/instances/publaynet.py +3 -3
  24. deepdoctection/datasets/instances/pubtables1m.py +18 -18
  25. deepdoctection/datasets/instances/pubtabnet.py +30 -29
  26. deepdoctection/datasets/instances/rvlcdip.py +28 -29
  27. deepdoctection/datasets/instances/xfund.py +51 -30
  28. deepdoctection/datasets/save.py +6 -6
  29. deepdoctection/eval/accmetric.py +32 -33
  30. deepdoctection/eval/base.py +8 -9
  31. deepdoctection/eval/cocometric.py +13 -12
  32. deepdoctection/eval/eval.py +32 -26
  33. deepdoctection/eval/tedsmetric.py +16 -12
  34. deepdoctection/eval/tp_eval_callback.py +7 -16
  35. deepdoctection/extern/base.py +339 -134
  36. deepdoctection/extern/d2detect.py +69 -89
  37. deepdoctection/extern/deskew.py +11 -10
  38. deepdoctection/extern/doctrocr.py +81 -64
  39. deepdoctection/extern/fastlang.py +23 -16
  40. deepdoctection/extern/hfdetr.py +53 -38
  41. deepdoctection/extern/hflayoutlm.py +216 -155
  42. deepdoctection/extern/hflm.py +35 -30
  43. deepdoctection/extern/model.py +433 -255
  44. deepdoctection/extern/pdftext.py +15 -15
  45. deepdoctection/extern/pt/ptutils.py +4 -2
  46. deepdoctection/extern/tessocr.py +39 -38
  47. deepdoctection/extern/texocr.py +14 -16
  48. deepdoctection/extern/tp/tfutils.py +16 -2
  49. deepdoctection/extern/tp/tpcompat.py +11 -7
  50. deepdoctection/extern/tp/tpfrcnn/config/config.py +4 -4
  51. deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +1 -1
  52. deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +5 -5
  53. deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +6 -6
  54. deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +4 -4
  55. deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +5 -3
  56. deepdoctection/extern/tp/tpfrcnn/preproc.py +5 -5
  57. deepdoctection/extern/tpdetect.py +40 -45
  58. deepdoctection/mapper/cats.py +36 -40
  59. deepdoctection/mapper/cocostruct.py +16 -12
  60. deepdoctection/mapper/d2struct.py +22 -22
  61. deepdoctection/mapper/hfstruct.py +7 -7
  62. deepdoctection/mapper/laylmstruct.py +22 -24
  63. deepdoctection/mapper/maputils.py +9 -10
  64. deepdoctection/mapper/match.py +33 -2
  65. deepdoctection/mapper/misc.py +6 -7
  66. deepdoctection/mapper/pascalstruct.py +4 -4
  67. deepdoctection/mapper/prodigystruct.py +6 -6
  68. deepdoctection/mapper/pubstruct.py +84 -92
  69. deepdoctection/mapper/tpstruct.py +3 -3
  70. deepdoctection/mapper/xfundstruct.py +33 -33
  71. deepdoctection/pipe/anngen.py +39 -14
  72. deepdoctection/pipe/base.py +68 -99
  73. deepdoctection/pipe/common.py +181 -85
  74. deepdoctection/pipe/concurrency.py +14 -10
  75. deepdoctection/pipe/doctectionpipe.py +24 -21
  76. deepdoctection/pipe/language.py +20 -25
  77. deepdoctection/pipe/layout.py +18 -16
  78. deepdoctection/pipe/lm.py +49 -47
  79. deepdoctection/pipe/order.py +63 -65
  80. deepdoctection/pipe/refine.py +102 -109
  81. deepdoctection/pipe/segment.py +157 -162
  82. deepdoctection/pipe/sub_layout.py +50 -40
  83. deepdoctection/pipe/text.py +37 -36
  84. deepdoctection/pipe/transform.py +19 -16
  85. deepdoctection/train/d2_frcnn_train.py +27 -25
  86. deepdoctection/train/hf_detr_train.py +22 -18
  87. deepdoctection/train/hf_layoutlm_train.py +49 -48
  88. deepdoctection/train/tp_frcnn_train.py +10 -11
  89. deepdoctection/utils/concurrency.py +1 -1
  90. deepdoctection/utils/context.py +13 -6
  91. deepdoctection/utils/develop.py +4 -4
  92. deepdoctection/utils/env_info.py +52 -14
  93. deepdoctection/utils/file_utils.py +6 -11
  94. deepdoctection/utils/fs.py +41 -14
  95. deepdoctection/utils/identifier.py +2 -2
  96. deepdoctection/utils/logger.py +15 -15
  97. deepdoctection/utils/metacfg.py +7 -7
  98. deepdoctection/utils/pdf_utils.py +39 -14
  99. deepdoctection/utils/settings.py +188 -182
  100. deepdoctection/utils/tqdm.py +1 -1
  101. deepdoctection/utils/transform.py +14 -9
  102. deepdoctection/utils/types.py +104 -0
  103. deepdoctection/utils/utils.py +7 -7
  104. deepdoctection/utils/viz.py +70 -69
  105. {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/METADATA +7 -4
  106. deepdoctection-0.34.dist-info/RECORD +146 -0
  107. {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/WHEEL +1 -1
  108. deepdoctection/utils/detection_types.py +0 -68
  109. deepdoctection-0.32.dist-info/RECORD +0 -146
  110. {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/LICENSE +0 -0
  111. {deepdoctection-0.32.dist-info → deepdoctection-0.34.dist-info}/top_level.txt +0 -0
@@ -79,8 +79,8 @@ def sample_fast_rcnn_targets(boxes, gt_boxes, gt_labels, frcnn_fg_thresh, frcnn_
79
79
  proposal_metrics(iou)
80
80
 
81
81
  # add ground truth as proposals as well
82
- boxes = tf.concat([boxes, gt_boxes], axis=0) # (n+m) x 4
83
- iou = tf.concat([iou, tf.eye(tf.shape(gt_boxes)[0])], axis=0) # (n+m) x m
82
+ boxes = tf.concat([boxes, gt_boxes], axis=0) # (n+m) x 4 # pylint: disable=E1123
83
+ iou = tf.concat([iou, tf.eye(tf.shape(gt_boxes)[0])], axis=0) # (n+m) x m # pylint: disable=E1123
84
84
  # #proposal=n+m from now on
85
85
 
86
86
  def sample_fg_bg(iou):
@@ -114,10 +114,10 @@ def sample_fast_rcnn_targets(boxes, gt_boxes, gt_labels, frcnn_fg_thresh, frcnn_
114
114
  )
115
115
  fg_inds_wrt_gt = tf.gather(best_iou_ind, fg_inds) # num_fg
116
116
 
117
- all_indices = tf.concat([fg_inds, bg_inds], axis=0) # indices w.r.t all n+m proposal boxes
117
+ all_indices = tf.concat([fg_inds, bg_inds], axis=0) # indices w.r.t all n+m proposal boxes # pylint: disable=E1123
118
118
  ret_boxes = tf.gather(boxes, all_indices)
119
119
 
120
- ret_labels = tf.concat(
120
+ ret_labels = tf.concat( # pylint: disable=E1123
121
121
  [tf.gather(gt_labels, fg_inds_wrt_gt), tf.zeros_like(bg_inds, dtype=tf.int64)],
122
122
  axis=0,
123
123
  )
@@ -47,7 +47,7 @@ def maskrcnn_loss(mask_logits, fg_labels, fg_target_masks):
47
47
 
48
48
  # add some training visualizations to tensorboard
49
49
  with tf.name_scope("mask_viz"):
50
- viz = tf.concat([fg_target_masks, mask_probs], axis=1)
50
+ viz = tf.concat([fg_target_masks, mask_probs], axis=1) # pylint: disable=E1123
51
51
  viz = tf.expand_dims(viz, 3)
52
52
  viz = tf.cast(viz * 255, tf.uint8, name="viz")
53
53
  tf.summary.image("mask_truth|pred", viz, max_outputs=10)
@@ -83,7 +83,7 @@ def maskrcnn_upXconv_head(feature, num_category, num_convs, norm=None, **kwargs)
83
83
  with argscope(
84
84
  [Conv2D, Conv2DTranspose],
85
85
  data_format="channels_first",
86
- kernel_initializer=tf.variance_scaling_initializer(
86
+ kernel_initializer=tf.variance_scaling_initializer( # pylint: disable=E1101
87
87
  scale=2.0,
88
88
  mode="fan_out",
89
89
  distribution="untruncated_normal" if get_tf_version_tuple() >= (1, 12) else "normal",
@@ -127,5 +127,7 @@ def unpackbits_masks(masks):
127
127
  assert masks.dtype == tf.uint8, masks
128
128
  bits = tf.constant((128, 64, 32, 16, 8, 4, 2, 1), dtype=tf.uint8)
129
129
  unpacked = tf.bitwise.bitwise_and(tf.expand_dims(masks, -1), bits) > 0
130
- unpacked = tf.reshape(unpacked, tf.concat([tf.shape(masks)[:-1], [8 * tf.shape(masks)[-1]]], axis=0))
130
+ unpacked = tf.reshape(
131
+ unpacked, tf.concat([tf.shape(masks)[:-1], [8 * tf.shape(masks)[-1]]], axis=0) # pylint: disable=E1123
132
+ ) # pylint: disable=E1123
131
133
  return unpacked
@@ -16,9 +16,9 @@ import numpy as np
16
16
  from lazy_imports import try_import
17
17
 
18
18
  from ....datapoint.convert import box_to_point4, point4_to_box
19
- from ....utils.detection_types import ImageType, JsonDict
20
19
  from ....utils.error import MalformedData
21
20
  from ....utils.logger import log_once
21
+ from ....utils.types import JsonDict, PixelValues
22
22
  from .common import filter_boxes_inside_shape, np_iou
23
23
  from .modeling.model_fpn import get_all_anchors_fpn
24
24
  from .utils.np_box_ops import area as np_area
@@ -214,15 +214,15 @@ def get_multilevel_rpn_anchor_input(
214
214
 
215
215
 
216
216
  def get_anchor_labels(
217
- anchors: ImageType,
218
- gt_boxes: ImageType,
219
- crowd_boxes: ImageType,
217
+ anchors: PixelValues,
218
+ gt_boxes: PixelValues,
219
+ crowd_boxes: PixelValues,
220
220
  batch_per_image: int,
221
221
  front_ground_ratio: float,
222
222
  positive_anchor_threshold: float,
223
223
  negative_anchor_threshold: float,
224
224
  crowd_overlap_threshold: float,
225
- ) -> (ImageType, ImageType):
225
+ ) -> (PixelValues, PixelValues):
226
226
  """
227
227
  Label each anchor as fg/bg/ignore.
228
228
 
@@ -18,17 +18,17 @@
18
18
  """
19
19
  TP Faster RCNN model as predictor for deepdoctection pipeline
20
20
  """
21
+ from __future__ import annotations
21
22
 
22
23
  from abc import ABC
23
- from copy import copy
24
24
  from pathlib import Path
25
- from typing import Dict, List, Mapping, Optional, Sequence, Union
25
+ from typing import Mapping, Optional, Sequence, Union
26
26
 
27
- from ..utils.detection_types import ImageType, Requirement
28
27
  from ..utils.file_utils import get_tensorflow_requirement, get_tensorpack_requirement
29
28
  from ..utils.metacfg import set_config_by_yaml
30
- from ..utils.settings import ObjectTypes, TypeOrStr, get_type
31
- from .base import DetectionResult, ObjectDetector, PredictorBase
29
+ from ..utils.settings import DefaultType, ObjectTypes, TypeOrStr, get_type
30
+ from ..utils.types import PathLikeOrStr, PixelValues, Requirement
31
+ from .base import DetectionResult, ModelCategories, ObjectDetector
32
32
  from .tp.tpcompat import TensorpackPredictor
33
33
  from .tp.tpfrcnn.config.config import model_frcnn_config
34
34
  from .tp.tpfrcnn.modeling.generalized_rcnn import ResNetFPNModel
@@ -38,41 +38,37 @@ from .tp.tpfrcnn.predict import tp_predict_image
38
38
  class TPFrcnnDetectorMixin(ObjectDetector, ABC):
39
39
  """Base class for TP FRCNN detector. This class only implements the basic wrapper functions"""
40
40
 
41
- def __init__(self, categories: Mapping[str, TypeOrStr], filter_categories: Optional[Sequence[TypeOrStr]] = None):
42
- self.categories = copy(categories) # type: ignore
41
+ def __init__(self, categories: Mapping[int, TypeOrStr], filter_categories: Optional[Sequence[TypeOrStr]] = None):
42
+ categories = {k: get_type(v) for k, v in categories.items()}
43
+ categories.update({0: get_type("background")})
44
+ self.categories = ModelCategories(categories)
43
45
  if filter_categories:
44
- filter_categories = [get_type(cat) for cat in filter_categories]
45
- self.filter_categories = filter_categories
46
- self._tp_categories = self._map_to_tp_categories(categories)
46
+ self.categories.filter_categories = tuple(get_type(cat) for cat in filter_categories)
47
47
 
48
- def _map_category_names(self, detection_results: List[DetectionResult]) -> List[DetectionResult]:
48
+ def _map_category_names(self, detection_results: list[DetectionResult]) -> list[DetectionResult]:
49
49
  """
50
50
  Populating category names to detection results
51
51
 
52
52
  :param detection_results: list of detection results
53
53
  :return: List of detection results with attribute class_name populated
54
54
  """
55
- filtered_detection_result: List[DetectionResult] = []
55
+ filtered_detection_result: list[DetectionResult] = []
56
56
  for result in detection_results:
57
- result.class_name = self._tp_categories[str(result.class_id)]
58
- if self.filter_categories:
59
- if result.class_name not in self.filter_categories:
60
- filtered_detection_result.append(result)
61
- else:
57
+ result.class_name = self.categories.categories.get(
58
+ result.class_id if result.class_id else -1, DefaultType.DEFAULT_TYPE
59
+ )
60
+ if result.class_name != DefaultType.DEFAULT_TYPE:
62
61
  filtered_detection_result.append(result)
63
62
  return filtered_detection_result
64
63
 
65
64
  @staticmethod
66
- def _map_to_tp_categories(categories: Mapping[str, TypeOrStr]) -> Dict[str, ObjectTypes]:
67
- categories = {str(key): get_type(categories[val]) for key, val in enumerate(categories, 1)}
68
- categories["0"] = get_type("background")
69
- return categories # type: ignore
70
-
71
- @staticmethod
72
- def get_name(path_weights: str, architecture: str) -> str:
65
+ def get_name(path_weights: PathLikeOrStr, architecture: str) -> str:
73
66
  """Returns the name of the model"""
74
67
  return f"Tensorpack_{architecture}" + "_".join(Path(path_weights).parts[-2:])
75
68
 
69
+ def get_category_names(self) -> tuple[ObjectTypes, ...]:
70
+ return self.categories.get_categories(as_dict=False)
71
+
76
72
 
77
73
  class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
78
74
  """
@@ -97,10 +93,10 @@ class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
97
93
 
98
94
  def __init__(
99
95
  self,
100
- path_yaml: str,
101
- path_weights: str,
102
- categories: Mapping[str, TypeOrStr],
103
- config_overwrite: Optional[List[str]] = None,
96
+ path_yaml: PathLikeOrStr,
97
+ path_weights: PathLikeOrStr,
98
+ categories: Mapping[int, TypeOrStr],
99
+ config_overwrite: Optional[list[str]] = None,
104
100
  ignore_mismatch: bool = False,
105
101
  filter_categories: Optional[Sequence[TypeOrStr]] = None,
106
102
  ):
@@ -125,14 +121,10 @@ class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
125
121
  :param filter_categories: The model might return objects that are not supposed to be predicted and that should
126
122
  be filtered. Pass a list of category names that must not be returned
127
123
  """
128
- self.path_yaml = path_yaml
129
-
130
- self.categories = copy(categories) # type: ignore
124
+ self.path_yaml = Path(path_yaml)
131
125
  self.config_overwrite = config_overwrite
132
- if filter_categories:
133
- filter_categories = [get_type(cat) for cat in filter_categories]
134
- self.filter_categories = filter_categories
135
- model = TPFrcnnDetector.get_wrapped_model(path_yaml, self.categories, config_overwrite)
126
+
127
+ model = TPFrcnnDetector.get_wrapped_model(path_yaml, categories, config_overwrite)
136
128
  TensorpackPredictor.__init__(self, model, path_weights, ignore_mismatch)
137
129
  TPFrcnnDetectorMixin.__init__(self, categories, filter_categories)
138
130
 
@@ -141,7 +133,7 @@ class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
141
133
 
142
134
  @staticmethod
143
135
  def get_wrapped_model(
144
- path_yaml: str, categories: Mapping[str, ObjectTypes], config_overwrite: Union[List[str], None]
136
+ path_yaml: PathLikeOrStr, categories: Mapping[int, TypeOrStr], config_overwrite: Union[list[str], None]
145
137
  ) -> ResNetFPNModel:
146
138
  """
147
139
  Calls all necessary methods to build TP ResNetFPNModel
@@ -163,7 +155,7 @@ class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
163
155
  model_frcnn_config(config=hyper_param_config, categories=categories, print_summary=False)
164
156
  return ResNetFPNModel(config=hyper_param_config)
165
157
 
166
- def predict(self, np_img: ImageType) -> List[DetectionResult]:
158
+ def predict(self, np_img: PixelValues) -> list[DetectionResult]:
167
159
  """
168
160
  Prediction per image.
169
161
 
@@ -180,15 +172,18 @@ class TPFrcnnDetector(TensorpackPredictor, TPFrcnnDetectorMixin):
180
172
  return self._map_category_names(detection_results)
181
173
 
182
174
  @classmethod
183
- def get_requirements(cls) -> List[Requirement]:
175
+ def get_requirements(cls) -> list[Requirement]:
184
176
  return [get_tensorflow_requirement(), get_tensorpack_requirement()]
185
177
 
186
- def clone(self) -> PredictorBase:
178
+ def clone(self) -> TPFrcnnDetector:
187
179
  return self.__class__(
188
- self.path_yaml,
189
- self.path_weights,
190
- self.categories,
191
- self.config_overwrite,
192
- self.ignore_mismatch,
193
- self.filter_categories,
180
+ path_yaml=self.path_yaml,
181
+ path_weights=self.path_weights,
182
+ categories=dict(self.categories.get_categories()),
183
+ config_overwrite=self.config_overwrite,
184
+ ignore_mismatch=self.ignore_mismatch,
185
+ filter_categories=self.categories.filter_categories,
194
186
  )
187
+
188
+ def clear_model(self) -> None:
189
+ self.tp_predictor = None
@@ -21,19 +21,19 @@ builder method of a dataset.
21
21
  """
22
22
 
23
23
  from collections import defaultdict
24
- from typing import Any, Dict, List, Literal, Mapping, Optional, Sequence, Tuple, Union
24
+ from typing import Any, Literal, Mapping, Optional, Sequence, Union
25
25
 
26
- from ..datapoint.annotation import CategoryAnnotation, ContainerAnnotation, ImageAnnotation, SummaryAnnotation
26
+ from ..datapoint.annotation import DEFAULT_CATEGORY_ID, CategoryAnnotation, ContainerAnnotation
27
27
  from ..datapoint.image import Image
28
- from ..utils.settings import ObjectTypes, TypeOrStr, get_type
28
+ from ..utils.settings import ObjectTypes, SummaryType, TypeOrStr, get_type
29
29
  from .maputils import LabelSummarizer, curry
30
30
 
31
31
 
32
32
  @curry
33
33
  def cat_to_sub_cat(
34
34
  dp: Image,
35
- categories_dict_names_as_key: Dict[TypeOrStr, str],
36
- cat_to_sub_cat_dict: Optional[Dict[TypeOrStr, TypeOrStr]] = None,
35
+ categories_dict_names_as_key: dict[TypeOrStr, int],
36
+ cat_to_sub_cat_dict: Optional[dict[TypeOrStr, TypeOrStr]] = None,
37
37
  ) -> Image:
38
38
  """
39
39
  Replace some category with its affiliated sub category of CategoryAnnotations. Suppose your category name is `foo`
@@ -49,13 +49,12 @@ def cat_to_sub_cat(
49
49
  if cat_to_sub_cat_dict is None:
50
50
  return dp
51
51
  cat_to_sub_cat_dict_obj_type = {get_type(key): get_type(value) for key, value in cat_to_sub_cat_dict.items()}
52
- categories_dict = categories_dict_names_as_key
53
- for ann in dp.get_annotation_iter(category_names=list(cat_to_sub_cat_dict_obj_type.keys())):
52
+ for ann in dp.get_annotation(category_names=list(cat_to_sub_cat_dict_obj_type.keys())):
54
53
  sub_cat_type = cat_to_sub_cat_dict_obj_type[get_type(ann.category_name)]
55
54
  sub_cat = ann.get_sub_category(sub_cat_type)
56
55
  if sub_cat:
57
56
  ann.category_name = sub_cat.category_name
58
- ann.category_id = categories_dict[ann.category_name]
57
+ ann.category_id = categories_dict_names_as_key[ann.category_name]
59
58
 
60
59
  return dp
61
60
 
@@ -63,7 +62,7 @@ def cat_to_sub_cat(
63
62
  @curry
64
63
  def re_assign_cat_ids(
65
64
  dp: Image,
66
- categories_dict_name_as_key: Optional[Dict[TypeOrStr, str]] = None,
65
+ categories_dict_name_as_key: Optional[dict[TypeOrStr, int]] = None,
67
66
  cat_to_sub_cat_mapping: Optional[Mapping[ObjectTypes, Any]] = None,
68
67
  ) -> Image:
69
68
  """
@@ -89,13 +88,13 @@ def re_assign_cat_ids(
89
88
  :return: Image
90
89
  """
91
90
 
92
- anns_to_remove: List[ImageAnnotation] = []
93
- for ann in dp.get_annotation_iter():
91
+ ann_ids_to_remove: list[str] = []
92
+ for ann in dp.get_annotation():
94
93
  if categories_dict_name_as_key is not None:
95
94
  if ann.category_name in categories_dict_name_as_key:
96
95
  ann.category_id = categories_dict_name_as_key[ann.category_name]
97
96
  else:
98
- anns_to_remove.append(ann)
97
+ ann_ids_to_remove.append(ann.annotation_id)
99
98
 
100
99
  if cat_to_sub_cat_mapping:
101
100
  if ann.category_name in cat_to_sub_cat_mapping:
@@ -103,17 +102,16 @@ def re_assign_cat_ids(
103
102
  for key in sub_cat_keys_to_sub_cat_values:
104
103
  sub_cat_values_dict = sub_cat_keys_to_sub_cat_values[key]
105
104
  sub_category = ann.get_sub_category(key)
106
- sub_category.category_id = sub_cat_values_dict.get(sub_category.category_name, "")
105
+ sub_category.category_id = sub_cat_values_dict.get(sub_category.category_name, DEFAULT_CATEGORY_ID)
107
106
 
108
- for ann in anns_to_remove:
109
- dp.remove(ann)
107
+ dp.remove(annotation_ids=ann_ids_to_remove)
110
108
 
111
109
  return dp
112
110
 
113
111
 
114
112
  @curry
115
113
  def filter_cat(
116
- dp: Image, categories_as_list_filtered: List[TypeOrStr], categories_as_list_unfiltered: List[TypeOrStr]
114
+ dp: Image, categories_as_list_filtered: list[TypeOrStr], categories_as_list_unfiltered: list[TypeOrStr]
117
115
  ) -> Image:
118
116
  """
119
117
  Filters category annotations based on the on a list of categories to be kept and a list of all possible
@@ -132,7 +130,7 @@ def filter_cat(
132
130
  remove_cats_mapper = remove_cats(category_names=cats_to_remove_list) # pylint: disable=E1120 # 259
133
131
  dp = remove_cats_mapper(dp)
134
132
 
135
- categories_dict_name_as_key = {v: str(k) for k, v in enumerate(categories_as_list_filtered, 1)}
133
+ categories_dict_name_as_key = {v: k for k, v in enumerate(categories_as_list_filtered, 1)}
136
134
  re_assign_cat_ids_mapper = re_assign_cat_ids( # pylint: disable=E1120
137
135
  categories_dict_name_as_key=categories_dict_name_as_key
138
136
  )
@@ -160,13 +158,13 @@ def filter_summary(
160
158
  :return: Image or None
161
159
  """
162
160
  for key, values in sub_cat_to_sub_cat_names_or_ids.items():
163
- if mode == "name" and dp.summary:
161
+ if mode == "name":
164
162
  if dp.summary.get_sub_category(get_type(key)).category_name in values:
165
163
  return dp
166
- elif mode == "value" and dp.summary:
164
+ elif mode == "value":
167
165
  if dp.summary.get_sub_category(get_type(key)).value in values: # type: ignore
168
166
  return dp
169
- elif dp.summary:
167
+ else:
170
168
  if dp.summary.get_sub_category(get_type(key)).category_id in values:
171
169
  return dp
172
170
  return None
@@ -179,7 +177,7 @@ def image_to_cat_id(
179
177
  sub_categories: Optional[Union[Mapping[TypeOrStr, TypeOrStr], Mapping[TypeOrStr, Sequence[TypeOrStr]]]] = None,
180
178
  summary_sub_category_names: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
181
179
  id_name_or_value: Literal["id", "name", "value"] = "id",
182
- ) -> Tuple[Dict[TypeOrStr, Union[List[int], List[int]]], str]:
180
+ ) -> tuple[dict[TypeOrStr, list[int]], str]:
183
181
  """
184
182
  Extracts all category_ids, sub category information or summary sub category information with given names into a
185
183
  defaultdict. This mapping is useful when running evaluation with e.g. an accuracy metric.
@@ -199,7 +197,7 @@ def image_to_cat_id(
199
197
 
200
198
  will return
201
199
 
202
- ({'foo':['1', '1'], 'bak':[ '2'], 'baz':['3']}, image_id)
200
+ ({'foo':[1,1], 'bak':[2], 'baz':[3]}, image_id)
203
201
 
204
202
 
205
203
  **Example 2:**
@@ -213,7 +211,7 @@ def image_to_cat_id(
213
211
 
214
212
  will return
215
213
 
216
- ({'foo_sub_1':['5', '6']}, image_id)
214
+ ({'foo_sub_1':[5,6]}, image_id)
217
215
 
218
216
 
219
217
 
@@ -238,7 +236,7 @@ def image_to_cat_id(
238
236
  if not summary_sub_category_names:
239
237
  summary_sub_category_names = []
240
238
 
241
- tmp_sub_category_names: Dict[str, Sequence[str]] = {}
239
+ tmp_sub_category_names: dict[str, Sequence[str]] = {}
242
240
 
243
241
  if sub_categories is not None:
244
242
  for key, val in sub_categories.items():
@@ -250,15 +248,15 @@ def image_to_cat_id(
250
248
  raise ValueError(f"id_name_or_value must be in ('id', 'name', 'value') but is {id_name_or_value}")
251
249
 
252
250
  if category_names or sub_categories:
253
- for ann in dp.get_annotation_iter():
251
+ for ann in dp.get_annotation():
254
252
  if ann.category_name in category_names:
255
- cat_container[ann.category_name].append(int(ann.category_id))
253
+ cat_container[ann.category_name].append(ann.category_id)
256
254
  if ann.category_name in tmp_sub_category_names:
257
255
  for sub_cat_name in tmp_sub_category_names[ann.category_name]:
258
256
  sub_cat = ann.get_sub_category(get_type(sub_cat_name))
259
257
  if sub_cat is not None:
260
258
  if id_name_or_value == "id":
261
- cat_container[sub_cat_name].append(int(sub_cat.category_id))
259
+ cat_container[sub_cat_name].append(sub_cat.category_id)
262
260
  if id_name_or_value == "name":
263
261
  cat_container[sub_cat_name].append(sub_cat.category_name) # type: ignore
264
262
  if id_name_or_value == "value":
@@ -269,11 +267,11 @@ def image_to_cat_id(
269
267
  )
270
268
  cat_container[sub_cat_name].append(sub_cat.value) # type: ignore
271
269
 
272
- if dp.summary is not None and summary_sub_category_names:
270
+ if summary_sub_category_names:
273
271
  for sub_cat_name in summary_sub_category_names:
274
272
  sub_cat = dp.summary.get_sub_category(get_type(sub_cat_name))
275
273
  if id_name_or_value == "id":
276
- cat_container[sub_cat_name].append(int(sub_cat.category_id))
274
+ cat_container[sub_cat_name].append(sub_cat.category_id)
277
275
  if id_name_or_value == "name":
278
276
  cat_container[sub_cat_name].append(sub_cat.category_name) # type: ignore
279
277
  if id_name_or_value == "value":
@@ -322,11 +320,11 @@ def remove_cats(
322
320
  if isinstance(summary_sub_categories, str):
323
321
  summary_sub_categories = [summary_sub_categories]
324
322
 
325
- anns_to_remove = []
323
+ ann_ids_to_remove = []
326
324
 
327
- for ann in dp.get_annotation_iter():
325
+ for ann in dp.get_annotation():
328
326
  if ann.category_name in category_names:
329
- anns_to_remove.append(ann)
327
+ ann_ids_to_remove.append(ann.annotation_id)
330
328
  if ann.category_name in sub_categories.keys():
331
329
  sub_cats_to_remove = sub_categories[ann.category_name]
332
330
  if isinstance(sub_cats_to_remove, str):
@@ -340,19 +338,17 @@ def remove_cats(
340
338
  for relation in relationships_to_remove:
341
339
  ann.remove_relationship(key=get_type(relation))
342
340
 
343
- for ann in anns_to_remove:
344
- dp.remove(ann)
341
+ dp.remove(annotation_ids=ann_ids_to_remove)
345
342
 
346
343
  if summary_sub_categories is not None:
347
- if dp.summary is not None:
348
- for sub_cat in summary_sub_categories:
349
- dp.summary.remove_sub_category(get_type(sub_cat))
344
+ for sub_cat in summary_sub_categories:
345
+ dp.summary.remove_sub_category(get_type(sub_cat))
350
346
 
351
347
  return dp
352
348
 
353
349
 
354
350
  @curry
355
- def add_summary(dp: Image, categories: Mapping[str, ObjectTypes]) -> Image:
351
+ def add_summary(dp: Image, categories: Mapping[int, ObjectTypes]) -> Image:
356
352
  """
357
353
  Adding a summary with the number of categories in an image.
358
354
 
@@ -366,10 +362,10 @@ def add_summary(dp: Image, categories: Mapping[str, ObjectTypes]) -> Image:
366
362
  for ann in anns:
367
363
  summarizer.dump(ann.category_id)
368
364
  summary_dict = summarizer.get_summary()
369
- summary = SummaryAnnotation()
365
+ summary = CategoryAnnotation(category_name=SummaryType.SUMMARY)
370
366
  for cat_id, val in summary_dict.items():
371
367
  summary.dump_sub_category(
372
- categories[cat_id], CategoryAnnotation(category_name=categories[cat_id], category_id=str(val))
368
+ categories[cat_id], CategoryAnnotation(category_name=categories[cat_id], category_id=val)
373
369
  )
374
370
  dp.summary = summary
375
371
  return dp
@@ -20,21 +20,21 @@ Module for mapping annotations in coco style structure
20
20
  """
21
21
 
22
22
  import os
23
- from typing import Dict, List, Mapping, Optional, Tuple
23
+ from typing import Mapping, Optional
24
24
 
25
25
  from ..datapoint.annotation import CategoryAnnotation, ImageAnnotation
26
26
  from ..datapoint.box import BoundingBox
27
27
  from ..datapoint.image import Image
28
- from ..utils.detection_types import JsonDict
29
28
  from ..utils.fs import load_image_from_file
30
29
  from ..utils.settings import ObjectTypes
30
+ from ..utils.types import CocoDatapointDict, JsonDict
31
31
  from .maputils import MappingContextManager, curry, maybe_get_fake_score
32
32
 
33
33
 
34
34
  @curry
35
35
  def coco_to_image(
36
- dp: JsonDict,
37
- categories: Dict[str, str],
36
+ dp: CocoDatapointDict,
37
+ categories: dict[int, ObjectTypes],
38
38
  load_image: bool,
39
39
  filter_empty_image: bool,
40
40
  fake_score: bool,
@@ -88,7 +88,7 @@ def coco_to_image(
88
88
  bbox = BoundingBox(absolute_coords=True, ulx=x_1, uly=y_1, height=h, width=w)
89
89
 
90
90
  annotation = ImageAnnotation(
91
- category_name=categories[str(ann["category_id"])],
91
+ category_name=categories[ann["category_id"]],
92
92
  bounding_box=bbox,
93
93
  category_id=ann["category_id"],
94
94
  score=maybe_get_fake_score(fake_score),
@@ -98,8 +98,8 @@ def coco_to_image(
98
98
 
99
99
  if coarse_sub_cat_name and coarse_mapping:
100
100
  sub_cat = CategoryAnnotation(
101
- category_name=categories[str(coarse_mapping[ann["category_id"]])],
102
- category_id=str(coarse_mapping[ann["category_id"]]),
101
+ category_name=categories[coarse_mapping[ann["category_id"]]],
102
+ category_id=coarse_mapping[ann["category_id"]],
103
103
  )
104
104
  annotation.dump_sub_category(coarse_sub_cat_name, sub_cat)
105
105
 
@@ -109,7 +109,7 @@ def coco_to_image(
109
109
  return image
110
110
 
111
111
 
112
- def image_to_coco(dp: Image) -> Tuple[JsonDict, List[JsonDict]]:
112
+ def image_to_coco(dp: Image) -> tuple[JsonDict, list[JsonDict]]:
113
113
  """
114
114
  Converting an image back into the coco format. As images and anns are separated it will return a dict with the
115
115
  image information and one for its annotations.
@@ -122,24 +122,28 @@ def image_to_coco(dp: Image) -> Tuple[JsonDict, List[JsonDict]]:
122
122
  raise TypeError(f"datapoints must be of type Image, is of type {type(dp)}")
123
123
 
124
124
  img: JsonDict = {}
125
- anns: List[JsonDict] = []
125
+ anns: list[JsonDict] = []
126
126
 
127
127
  img["id"] = int("".join([s for s in dp.image_id if s.isdigit()]))
128
128
  img["width"] = dp.width
129
129
  img["height"] = dp.height
130
130
  img["file_name"] = dp.file_name
131
131
 
132
- for img_ann in dp.get_annotation_iter():
132
+ for img_ann in dp.get_annotation():
133
133
  ann: JsonDict = {
134
134
  "id": int("".join([s for s in img_ann.annotation_id if s.isdigit()])),
135
135
  "image_id": img["id"],
136
- "category_id": int(img_ann.category_id),
136
+ "category_id": img_ann.category_id,
137
137
  }
138
138
  if img_ann.score:
139
139
  ann["score"] = img_ann.score
140
140
  ann["iscrowd"] = 0
141
141
  bounding_box = img_ann.get_bounding_box(dp.image_id)
142
- ann["area"] = bounding_box.area
142
+ ann["area"] = (
143
+ bounding_box.area
144
+ if bounding_box.absolute_coords
145
+ else bounding_box.transform(dp.width, dp.height, absolute_coords=True).area
146
+ )
143
147
  ann["bbox"] = bounding_box.to_list(mode="xywh")
144
148
  anns.append(ann)
145
149