deepdoctection 0.42.0__py3-none-any.whl → 0.43__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 (124) hide show
  1. deepdoctection/__init__.py +2 -1
  2. deepdoctection/analyzer/__init__.py +2 -1
  3. deepdoctection/analyzer/config.py +904 -0
  4. deepdoctection/analyzer/dd.py +36 -62
  5. deepdoctection/analyzer/factory.py +311 -141
  6. deepdoctection/configs/conf_dd_one.yaml +100 -44
  7. deepdoctection/configs/profiles.jsonl +32 -0
  8. deepdoctection/dataflow/__init__.py +9 -6
  9. deepdoctection/dataflow/base.py +33 -15
  10. deepdoctection/dataflow/common.py +96 -75
  11. deepdoctection/dataflow/custom.py +36 -29
  12. deepdoctection/dataflow/custom_serialize.py +135 -91
  13. deepdoctection/dataflow/parallel_map.py +33 -31
  14. deepdoctection/dataflow/serialize.py +15 -10
  15. deepdoctection/dataflow/stats.py +41 -28
  16. deepdoctection/datapoint/__init__.py +4 -6
  17. deepdoctection/datapoint/annotation.py +104 -66
  18. deepdoctection/datapoint/box.py +190 -130
  19. deepdoctection/datapoint/convert.py +66 -39
  20. deepdoctection/datapoint/image.py +151 -95
  21. deepdoctection/datapoint/view.py +383 -236
  22. deepdoctection/datasets/__init__.py +2 -6
  23. deepdoctection/datasets/adapter.py +11 -11
  24. deepdoctection/datasets/base.py +118 -81
  25. deepdoctection/datasets/dataflow_builder.py +18 -12
  26. deepdoctection/datasets/info.py +76 -57
  27. deepdoctection/datasets/instances/__init__.py +6 -2
  28. deepdoctection/datasets/instances/doclaynet.py +17 -14
  29. deepdoctection/datasets/instances/fintabnet.py +16 -22
  30. deepdoctection/datasets/instances/funsd.py +11 -6
  31. deepdoctection/datasets/instances/iiitar13k.py +9 -9
  32. deepdoctection/datasets/instances/layouttest.py +9 -9
  33. deepdoctection/datasets/instances/publaynet.py +9 -9
  34. deepdoctection/datasets/instances/pubtables1m.py +13 -13
  35. deepdoctection/datasets/instances/pubtabnet.py +13 -15
  36. deepdoctection/datasets/instances/rvlcdip.py +8 -8
  37. deepdoctection/datasets/instances/xfund.py +11 -9
  38. deepdoctection/datasets/registry.py +18 -11
  39. deepdoctection/datasets/save.py +12 -11
  40. deepdoctection/eval/__init__.py +3 -2
  41. deepdoctection/eval/accmetric.py +72 -52
  42. deepdoctection/eval/base.py +29 -10
  43. deepdoctection/eval/cocometric.py +14 -12
  44. deepdoctection/eval/eval.py +56 -41
  45. deepdoctection/eval/registry.py +6 -3
  46. deepdoctection/eval/tedsmetric.py +24 -9
  47. deepdoctection/eval/tp_eval_callback.py +13 -12
  48. deepdoctection/extern/__init__.py +1 -1
  49. deepdoctection/extern/base.py +176 -97
  50. deepdoctection/extern/d2detect.py +127 -92
  51. deepdoctection/extern/deskew.py +19 -10
  52. deepdoctection/extern/doctrocr.py +157 -106
  53. deepdoctection/extern/fastlang.py +25 -17
  54. deepdoctection/extern/hfdetr.py +137 -60
  55. deepdoctection/extern/hflayoutlm.py +329 -248
  56. deepdoctection/extern/hflm.py +67 -33
  57. deepdoctection/extern/model.py +108 -762
  58. deepdoctection/extern/pdftext.py +37 -12
  59. deepdoctection/extern/pt/nms.py +15 -1
  60. deepdoctection/extern/pt/ptutils.py +13 -9
  61. deepdoctection/extern/tessocr.py +87 -54
  62. deepdoctection/extern/texocr.py +29 -14
  63. deepdoctection/extern/tp/tfutils.py +36 -8
  64. deepdoctection/extern/tp/tpcompat.py +54 -16
  65. deepdoctection/extern/tp/tpfrcnn/config/config.py +20 -4
  66. deepdoctection/extern/tpdetect.py +4 -2
  67. deepdoctection/mapper/__init__.py +1 -1
  68. deepdoctection/mapper/cats.py +117 -76
  69. deepdoctection/mapper/cocostruct.py +35 -17
  70. deepdoctection/mapper/d2struct.py +56 -29
  71. deepdoctection/mapper/hfstruct.py +32 -19
  72. deepdoctection/mapper/laylmstruct.py +221 -185
  73. deepdoctection/mapper/maputils.py +71 -35
  74. deepdoctection/mapper/match.py +76 -62
  75. deepdoctection/mapper/misc.py +68 -44
  76. deepdoctection/mapper/pascalstruct.py +13 -12
  77. deepdoctection/mapper/prodigystruct.py +33 -19
  78. deepdoctection/mapper/pubstruct.py +42 -32
  79. deepdoctection/mapper/tpstruct.py +39 -19
  80. deepdoctection/mapper/xfundstruct.py +20 -13
  81. deepdoctection/pipe/__init__.py +1 -2
  82. deepdoctection/pipe/anngen.py +104 -62
  83. deepdoctection/pipe/base.py +226 -107
  84. deepdoctection/pipe/common.py +206 -123
  85. deepdoctection/pipe/concurrency.py +74 -47
  86. deepdoctection/pipe/doctectionpipe.py +108 -47
  87. deepdoctection/pipe/language.py +41 -24
  88. deepdoctection/pipe/layout.py +45 -18
  89. deepdoctection/pipe/lm.py +146 -78
  90. deepdoctection/pipe/order.py +196 -113
  91. deepdoctection/pipe/refine.py +111 -63
  92. deepdoctection/pipe/registry.py +1 -1
  93. deepdoctection/pipe/segment.py +213 -142
  94. deepdoctection/pipe/sub_layout.py +76 -46
  95. deepdoctection/pipe/text.py +52 -33
  96. deepdoctection/pipe/transform.py +8 -6
  97. deepdoctection/train/d2_frcnn_train.py +87 -69
  98. deepdoctection/train/hf_detr_train.py +72 -40
  99. deepdoctection/train/hf_layoutlm_train.py +85 -46
  100. deepdoctection/train/tp_frcnn_train.py +56 -28
  101. deepdoctection/utils/concurrency.py +59 -16
  102. deepdoctection/utils/context.py +40 -19
  103. deepdoctection/utils/develop.py +25 -17
  104. deepdoctection/utils/env_info.py +85 -36
  105. deepdoctection/utils/error.py +16 -10
  106. deepdoctection/utils/file_utils.py +246 -62
  107. deepdoctection/utils/fs.py +162 -43
  108. deepdoctection/utils/identifier.py +29 -16
  109. deepdoctection/utils/logger.py +49 -32
  110. deepdoctection/utils/metacfg.py +83 -21
  111. deepdoctection/utils/pdf_utils.py +119 -62
  112. deepdoctection/utils/settings.py +24 -10
  113. deepdoctection/utils/tqdm.py +10 -5
  114. deepdoctection/utils/transform.py +182 -46
  115. deepdoctection/utils/utils.py +61 -28
  116. deepdoctection/utils/viz.py +150 -104
  117. deepdoctection-0.43.dist-info/METADATA +376 -0
  118. deepdoctection-0.43.dist-info/RECORD +149 -0
  119. {deepdoctection-0.42.0.dist-info → deepdoctection-0.43.dist-info}/WHEEL +1 -1
  120. deepdoctection/analyzer/_config.py +0 -146
  121. deepdoctection-0.42.0.dist-info/METADATA +0 -431
  122. deepdoctection-0.42.0.dist-info/RECORD +0 -148
  123. {deepdoctection-0.42.0.dist-info → deepdoctection-0.43.dist-info}/licenses/LICENSE +0 -0
  124. {deepdoctection-0.42.0.dist-info → deepdoctection-0.43.dist-info}/top_level.txt +0 -0
@@ -46,18 +46,22 @@ elif os.environ.get("DD_USE_TF"):
46
46
  @pipeline_component_registry.register("ImageCroppingService")
47
47
  class ImageCroppingService(PipelineComponent):
48
48
  """
49
- Crop sub images given by bounding boxes of some annotations. This service is not necessary for
50
- `ImageLayoutService` and is more intended for saved files where sub images are
49
+ Crop sub images given by bounding boxes of some annotations.
50
+
51
+ This service is not necessary for `ImageLayoutService` and is more intended for saved files where sub images are
51
52
  generally not stored.
53
+
52
54
  """
53
55
 
54
56
  def __init__(
55
- self,
56
- category_names: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
57
- service_ids: Optional[Sequence[str]] = None,
57
+ self,
58
+ category_names: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
59
+ service_ids: Optional[Sequence[str]] = None,
58
60
  ) -> None:
59
61
  """
60
- :param category_names: A single name or a list of category names to crop
62
+ Args:
63
+ category_names: A single name or a list of category names to crop.
64
+ service_ids: Optional list of service IDs.
61
65
  """
62
66
  if category_names is None:
63
67
  self.category_names = None
@@ -86,42 +90,46 @@ class ImageCroppingService(PipelineComponent):
86
90
 
87
91
  class IntersectionMatcher:
88
92
  """
89
- Objects of two object classes can be assigned to one another by determining their pairwise intersection. If this is
90
- above a limit, a relation is created between them.
93
+ Objects of two object classes can be assigned to one another by determining their pairwise intersection.
94
+ If this is above a limit, a relation is created between them.
95
+
91
96
  The parent object class (based on its category) and the child object class are defined for the service.
92
97
 
93
98
  Either `iou` (intersection-over-union) or `ioa` (intersection-over-area) can be selected as the matching rule.
94
99
 
95
- # the following will assign word annotations to text and title annotation, provided that their ioa-threshold
96
- # is above 0.7. words below that threshold will not be assigned.
97
-
98
- matcher = IntersectionMatcher(matching_rule="ioa", threshold=0.7)
99
-
100
- match_service = MatchingService(parent_categories=["text","title"],
101
- child_categories="word",
102
- matcher=matcher,
103
- relationship_key=Relationships.CHILD)
100
+ Example:
101
+ ```python
102
+ matcher = IntersectionMatcher(matching_rule="ioa", threshold=0.7)
103
+ match_service = MatchingService(parent_categories=["text","title"],
104
+ child_categories="word",
105
+ matcher=matcher,
106
+ relationship_key=Relationships.CHILD)
107
+ ```
104
108
 
105
- # Assigning means that text and title annotation will receive a relationship called "CHILD" which is a list
106
- of annotation ids of mapped words.
109
+ Assigning means that text and title annotation will receive a relationship called `CHILD` which is a list
110
+ of annotation ids of mapped words.
107
111
  """
108
112
 
109
113
  def __init__(
110
- self,
111
- matching_rule: Literal["iou", "ioa"],
112
- threshold: float,
113
- use_weighted_intersections: bool = False,
114
- max_parent_only: bool = False,
114
+ self,
115
+ matching_rule: Literal["iou", "ioa"],
116
+ threshold: float,
117
+ use_weighted_intersections: bool = False,
118
+ max_parent_only: bool = False,
115
119
  ) -> None:
116
120
  """
117
- :param matching_rule: "iou" or "ioa"
118
- :param threshold: iou/ioa threshold. Value between [0,1]
119
- :param use_weighted_intersections: This is currently only implemented for matching_rule 'ioa'. Instead of using
120
- the ioa_matrix it will use mat weighted ioa in order to take into account
121
- that intersections with more cells will likely decrease the ioa value. By
122
- multiplying the ioa with the number of all intersection for each child this
123
- value calibrate the ioa.
124
- :param max_parent_only: Will assign to each child at most one parent with maximum ioa"""
121
+ Args:
122
+ matching_rule: `iou` or `ioa`.
123
+ threshold: iou/ioa threshold. Value between [0,1].
124
+ use_weighted_intersections: This is currently only implemented for matching_rule `ioa`. Instead of using
125
+ the ioa_matrix it will use mat weighted ioa in order to take into account that intersections with more
126
+ cells will likely decrease the ioa value. By multiplying the ioa with the number of all intersection for
127
+ each child this value calibrate the ioa.
128
+ max_parent_only: Will assign to each child at most one parent with maximum ioa.
129
+
130
+ Raises:
131
+ ValueError: If `matching_rule` is not `iou` or `ioa`.
132
+ """
125
133
 
126
134
  if matching_rule not in ("iou", "ioa"):
127
135
  raise ValueError("segment rule must be either iou or ioa")
@@ -131,25 +139,27 @@ class IntersectionMatcher:
131
139
  self.max_parent_only = max_parent_only
132
140
 
133
141
  def match(
134
- self,
135
- dp: Image,
136
- parent_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
137
- child_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
138
- parent_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
139
- child_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
142
+ self,
143
+ dp: Image,
144
+ parent_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
145
+ child_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
146
+ parent_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
147
+ child_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
140
148
  ) -> list[tuple[str, str]]:
141
149
  """
142
- The matching algorithm
143
-
144
- :param dp: datapoint image
145
- :param parent_categories: list of categories to be used a for parent class. Will generate a child-relationship
146
- :param child_categories: list of categories to be used for a child class.
147
- :param parent_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
148
- parent candidates which are not in the list.
149
- :param child_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
150
- children candidates which are not in the list.
151
-
152
- :return: A list of tuples with parent and child annotation ids
150
+ The matching algorithm.
151
+
152
+ Args:
153
+ dp: `Image` datapoint.
154
+ parent_categories: List of categories to be used as parent class. Will generate a child-relationship.
155
+ child_categories: List of categories to be used for a child class.
156
+ parent_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
157
+ parent candidates which are not in the list.
158
+ child_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
159
+ children candidates which are not in the list.
160
+
161
+ Returns:
162
+ A list of tuples with parent and child annotation ids.
153
163
  """
154
164
  child_index, parent_index, child_anns, parent_anns = match_anns_by_intersection(
155
165
  dp,
@@ -177,37 +187,38 @@ class NeighbourMatcher:
177
187
  """
178
188
  Objects of two object classes can be assigned to one another by determining their pairwise distance.
179
189
 
180
- # the following will assign caption annotations to figure annotation
181
-
190
+ Example:
191
+ ```python
182
192
  matcher = NeighbourMatcher()
183
-
184
193
  match_service = MatchingService(parent_categories=["figure"],
185
194
  child_categories="caption",
186
195
  matcher=matcher,
187
196
  relationship_key=Relationships.LAYOUT_LINK)
188
-
197
+ ```
189
198
  """
190
199
 
191
200
  def match(
192
- self,
193
- dp: Image,
194
- parent_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
195
- child_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
196
- parent_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
197
- child_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
201
+ self,
202
+ dp: Image,
203
+ parent_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
204
+ child_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
205
+ parent_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
206
+ child_ann_service_ids: Optional[Union[str, Sequence[str]]] = None,
198
207
  ) -> list[tuple[str, str]]:
199
208
  """
200
- The matching algorithm
201
-
202
- :param dp: datapoint image
203
- :param parent_categories: list of categories to be used a for parent class. Will generate a child-relationship
204
- :param child_categories: list of categories to be used for a child class.
205
- :param parent_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
206
- parent candidates which are not in the list.
207
- :param child_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
208
- children candidates which are not in the list.
209
-
210
- :return: A list of tuples with parent and child annotation ids
209
+ The matching algorithm.
210
+
211
+ Args:
212
+ dp: `Image` datapoint.
213
+ parent_categories: List of categories to be used as parent class. Will generate a child-relationship.
214
+ child_categories: List of categories to be used for a child class.
215
+ parent_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
216
+ parent candidates which are not in the list.
217
+ child_ann_service_ids: Additional filter condition. If some ids are selected, it will ignore all other
218
+ children candidates which are not in the list.
219
+
220
+ Returns:
221
+ A list of tuples with parent and child annotation ids.
211
222
  """
212
223
 
213
224
  return [
@@ -225,8 +236,17 @@ class NeighbourMatcher:
225
236
  @dataclass
226
237
  class FamilyCompound:
227
238
  """
228
- A family compound is a set of parent and child categories that are related by a relationship key. The parent
229
- categories will receive a relationship to the child categories.
239
+ A family compound is a set of parent and child categories that are related by a relationship key.
240
+ The parent categories will receive a relationship to the child categories.
241
+
242
+ Attributes:
243
+ relationship_key: The relationship key.
244
+ parent_categories: Parent categories.
245
+ child_categories: Child categories.
246
+ parent_ann_service_ids: Parent annotation service IDs.
247
+ child_ann_service_ids: Child annotation service IDs.
248
+ create_synthetic_parent: Whether to create a synthetic parent.
249
+ synthetic_parent: The synthetic parent.
230
250
  """
231
251
 
232
252
  relationship_key: Relationships
@@ -255,18 +275,23 @@ class FamilyCompound:
255
275
  @pipeline_component_registry.register("MatchingService")
256
276
  class MatchingService(PipelineComponent):
257
277
  """
258
- A service to match annotations of two categories by intersection or distance. The matched annotations will be
259
- assigned a relationship. The parent category will receive a relationship to the child category.
278
+ A service to match annotations of two categories by intersection or distance.
279
+
280
+ The matched annotations will be assigned a relationship. The parent category will receive a
281
+ relationship to the child category.
282
+
283
+
260
284
  """
261
285
 
262
286
  def __init__(
263
- self,
264
- family_compounds: Sequence[FamilyCompound],
265
- matcher: Union[IntersectionMatcher, NeighbourMatcher],
287
+ self,
288
+ family_compounds: Sequence[FamilyCompound],
289
+ matcher: Union[IntersectionMatcher, NeighbourMatcher],
266
290
  ) -> None:
267
291
  """
268
- :param family_compounds: A list of FamilyCompounds
269
- :param matcher: A matcher object
292
+ Args:
293
+ family_compounds: A list of `FamilyCompound`.
294
+ matcher: A matcher object.
270
295
  """
271
296
  self.family_compounds = family_compounds
272
297
  self.matcher = matcher
@@ -274,10 +299,10 @@ class MatchingService(PipelineComponent):
274
299
 
275
300
  def serve(self, dp: Image) -> None:
276
301
  """
277
- - generates pairwise match-score by intersection
278
- - generates child relationship at parent level
302
+ Generates pairwise match-score by intersection and generates child relationship at parent level.
279
303
 
280
- :param dp: datapoint image
304
+ Args:
305
+ dp: `Image` datapoint.
281
306
  """
282
307
  for family_compound in self.family_compounds:
283
308
  matched_pairs = self.matcher.match(
@@ -300,18 +325,22 @@ class MatchingService(PipelineComponent):
300
325
  detect_result_list = []
301
326
  for child_ann in child_anns:
302
327
  if child_ann.annotation_id not in child_ann_ids:
303
- detect_result_list.append(DetectionResult(
304
- class_name=family_compound.synthetic_parent,
305
- box=child_ann.get_bounding_box(dp.image_id).to_list(mode="xyxy"),
306
- absolute_coords=child_ann.get_bounding_box(dp.image_id).absolute_coords,
307
- relationships={family_compound.relationship_key: child_ann.annotation_id}))
328
+ detect_result_list.append(
329
+ DetectionResult(
330
+ class_name=family_compound.synthetic_parent,
331
+ box=child_ann.get_bounding_box(dp.image_id).to_list(mode="xyxy"),
332
+ absolute_coords=child_ann.get_bounding_box(dp.image_id).absolute_coords,
333
+ relationships={family_compound.relationship_key: child_ann.annotation_id},
334
+ )
335
+ )
308
336
  for detect_result in detect_result_list:
309
337
  annotation_id = self.dp_manager.set_image_annotation(detect_result)
310
338
  if annotation_id is not None and detect_result.relationships is not None:
311
- self.dp_manager.set_relationship_annotation(family_compound.relationship_key,
312
- annotation_id,
313
- detect_result.relationships.get(
314
- family_compound.relationship_key, None))
339
+ self.dp_manager.set_relationship_annotation(
340
+ family_compound.relationship_key,
341
+ annotation_id,
342
+ detect_result.relationships.get(family_compound.relationship_key, None),
343
+ )
315
344
 
316
345
  def clone(self) -> PipelineComponent:
317
346
  return self.__class__(self.family_compounds, self.matcher)
@@ -336,31 +365,44 @@ class MatchingService(PipelineComponent):
336
365
  @pipeline_component_registry.register("PageParsingService")
337
366
  class PageParsingService(PipelineComponent):
338
367
  """
339
- A "pseudo" pipeline component that can be added to a pipeline to convert `Image`s into `Page` formats. It allows a
340
- custom parsing depending on customizing options of other pipeline components.
368
+ A "pseudo" pipeline component that can be added to a pipeline to convert `Image`s into `Page` formats.
369
+
370
+ It allows a custom parsing depending on customizing options of other pipeline components.
371
+
372
+ Info:
373
+ This component is not meant to be used in the `serve` method.
341
374
  """
342
375
 
343
376
  def __init__(
344
- self,
345
- text_container: TypeOrStr,
346
- floating_text_block_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
347
- include_residual_text_container: bool = True,
377
+ self,
378
+ text_container: TypeOrStr,
379
+ floating_text_block_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
380
+ residual_text_block_categories: Optional[Union[TypeOrStr, Sequence[TypeOrStr]]] = None,
381
+ include_residual_text_container: bool = True,
348
382
  ):
349
383
  """
350
- :param text_container: name of an image annotation that has a CHARS sub category. These annotations will be
351
- ordered within all text blocks.
352
- :param floating_text_block_categories: name of image annotation that have a relation with text containers.
384
+ Args:
385
+ text_container: Name of an image annotation that has a `CHARS` sub category. These annotations will be
386
+ ordered within all text blocks.
387
+ floating_text_block_categories: Name of image annotation that have a relation with text containers.
388
+ residual_text_block_categories: Name of image annotation that have a relation with text containers.
389
+ include_residual_text_container: Whether to include residual text container.
353
390
  """
354
391
  self.name = "page_parser"
355
392
  if isinstance(floating_text_block_categories, (str, ObjectTypes)):
356
393
  floating_text_block_categories = (get_type(floating_text_block_categories),)
357
394
  if floating_text_block_categories is None:
358
- floating_text_block_categories = IMAGE_DEFAULTS["floating_text_block_categories"]
395
+ floating_text_block_categories = IMAGE_DEFAULTS.FLOATING_TEXT_BLOCK_CATEGORIES
396
+ if residual_text_block_categories is None:
397
+ residual_text_block_categories = IMAGE_DEFAULTS.RESIDUAL_TEXT_BLOCK_CATEGORIES
359
398
 
360
399
  self.text_container = get_type(text_container)
361
400
  self.floating_text_block_categories = tuple(
362
401
  (get_type(text_block) for text_block in floating_text_block_categories)
363
402
  )
403
+ self.residual_text_block_categories = tuple(
404
+ get_type(text_block) for text_block in residual_text_block_categories
405
+ )
364
406
  self.include_residual_text_container = include_residual_text_container
365
407
  self._init_sanity_checks()
366
408
  super().__init__(self.name)
@@ -370,14 +412,19 @@ class PageParsingService(PipelineComponent):
370
412
 
371
413
  def pass_datapoint(self, dp: Image) -> Page:
372
414
  """
373
- converts Image to Page
374
- :param dp: Image
375
- :return: Page
415
+ Converts `Image` to `Page`.
416
+
417
+ Args:
418
+ dp: `Image`.
419
+
420
+ Returns:
421
+ `Page`.
376
422
  """
377
423
  return Page.from_image(
378
424
  dp,
379
425
  text_container=self.text_container,
380
426
  floating_text_block_categories=self.floating_text_block_categories,
427
+ residual_text_block_categories=self.residual_text_block_categories,
381
428
  include_residual_text_container=self.include_residual_text_container,
382
429
  )
383
430
 
@@ -389,15 +436,22 @@ class PageParsingService(PipelineComponent):
389
436
 
390
437
  def get_meta_annotation(self) -> MetaAnnotation:
391
438
  """
392
- meta annotation. We do not generate any new annotations here
439
+ Returns:
440
+ `MetaAnnotation`. No new annotations are generated here.
393
441
  """
394
442
  return MetaAnnotation(image_annotations=(), sub_categories={}, relationships={}, summaries=())
395
443
 
396
444
  def clone(self) -> PageParsingService:
397
- """clone"""
445
+ """
446
+ Clone the `PageParsingService`.
447
+
448
+ Returns:
449
+ A cloned `PageParsingService`.
450
+ """
398
451
  return self.__class__(
399
452
  deepcopy(self.text_container),
400
453
  deepcopy(self.floating_text_block_categories),
454
+ deepcopy(self.residual_text_block_categories),
401
455
  self.include_residual_text_container,
402
456
  )
403
457
 
@@ -409,15 +463,18 @@ class PageParsingService(PipelineComponent):
409
463
  class AnnotationNmsService(PipelineComponent):
410
464
  """
411
465
  A service to pass `ImageAnnotation` to a non-maximum suppression (NMS) process for given pairs of categories.
466
+
412
467
  `ImageAnnotation`s are subjected to NMS process in groups:
413
468
  If `nms_pairs=[[LayoutType.text, LayoutType.table],[LayoutType.title, LayoutType.table]]` all `ImageAnnotation`
414
469
  subject to these categories are being selected and identified as one category.
415
470
  After NMS the discarded image annotation will be deactivated.
416
471
 
417
- **Example**
418
-
472
+ Example:
473
+ ```python
419
474
  AnnotationNmsService(nms_pairs=[[LayoutType.text, LayoutType.table],[LayoutType.title, LayoutType.table]],
420
- thresholds=[0.7,0.7]) # for each pair a threshold has to be provided
475
+ thresholds=[0.7,0.7])
476
+ ```
477
+ For each pair a threshold has to be provided.
421
478
 
422
479
  For a pair of categories, one can also select a category which has always priority even if the score is lower.
423
480
  This is useful if one expects some categories to be larger and want to keep them.
@@ -426,15 +483,20 @@ class AnnotationNmsService(PipelineComponent):
426
483
  """
427
484
 
428
485
  def __init__(
429
- self,
430
- nms_pairs: Sequence[Sequence[TypeOrStr]],
431
- thresholds: Union[float, Sequence[float]],
432
- priority: Optional[Sequence[Union[Optional[TypeOrStr]]]] = None,
486
+ self,
487
+ nms_pairs: Sequence[Sequence[TypeOrStr]],
488
+ thresholds: Union[float, Sequence[float]],
489
+ priority: Optional[Sequence[Union[Optional[TypeOrStr]]]] = None,
433
490
  ):
434
491
  """
435
- :param nms_pairs: Groups of categories, either as string or by `ObjectType`.
436
- :param thresholds: Suppression threshold. If only one value is provided, it will apply the threshold to all
437
- pairs. If a list is provided, make sure to add as many list elements as `nms_pairs`.
492
+ Args:
493
+ nms_pairs: Groups of categories, either as string or by `ObjectType`.
494
+ thresholds: Suppression threshold. If only one value is provided, it will apply the threshold to all
495
+ pairs. If a list is provided, make sure to add as many list elements as `nms_pairs`.
496
+ priority: Optional list of categories which have always priority.
497
+
498
+ Raises:
499
+ AssertionError: If the length of `nms_pairs` and `thresholds` or `priority` do not match.
438
500
  """
439
501
  self.nms_pairs = [[get_type(val) for val in pair] for pair in nms_pairs]
440
502
  if isinstance(thresholds, float):
@@ -456,6 +518,13 @@ class AnnotationNmsService(PipelineComponent):
456
518
  super().__init__("nms")
457
519
 
458
520
  def serve(self, dp: Image) -> None:
521
+ """
522
+ Args:
523
+ dp: `Image`.
524
+
525
+ Returns:
526
+ None.
527
+ """
459
528
  for pair, threshold, prio in zip(self.nms_pairs, self.threshold, self.priority):
460
529
  anns = dp.get_annotation(category_names=pair)
461
530
  ann_ids_to_keep = nms_image_annotations(anns, threshold, dp.image_id, prio)
@@ -476,27 +545,41 @@ class AnnotationNmsService(PipelineComponent):
476
545
  @pipeline_component_registry.register("ImageParsingService")
477
546
  class ImageParsingService:
478
547
  """
479
- A super light service that calls `to_image` when processing datapoints. Might be useful if you build a pipeline that
480
- is not derived from `DoctectionPipe`.
548
+ A super light service that calls `to_image` when processing datapoints.
549
+
550
+ Might be useful if you build a pipeline that is not derived from `DoctectionPipe`.
551
+
481
552
  """
482
553
 
483
554
  def __init__(self, dpi: Optional[int] = None):
484
555
  """
485
- :param dpi: dpi resolution when converting PDFs into pixel values
556
+ Args:
557
+ dpi: dpi resolution when converting PDFs into pixel values.
486
558
  """
487
559
  self.name = "image"
488
560
  self.dpi = dpi
489
561
 
490
562
  def pass_datapoint(self, dp: Union[str, Mapping[str, Union[str, bytes]]]) -> Optional[Image]:
491
- """pass a datapoint"""
563
+ """
564
+ Pass a datapoint.
565
+
566
+ Args:
567
+ dp: A datapoint, either a string or a mapping.
568
+
569
+ Returns:
570
+ `Image` or None.
571
+ """
492
572
  return to_image(dp, self.dpi)
493
573
 
494
574
  def predict_dataflow(self, df: DataFlow) -> DataFlow:
495
575
  """
496
- Mapping a datapoint via `pass_datapoint` within a dataflow pipeline
576
+ Mapping a datapoint via `pass_datapoint` within a dataflow pipeline.
577
+
578
+ Args:
579
+ df: An input `DataFlow`.
497
580
 
498
- :param df: An input dataflow
499
- :return: A output dataflow
581
+ Returns:
582
+ An output `DataFlow`.
500
583
  """
501
584
  return MapData(df, self.pass_datapoint)
502
585