deepdoctection 0.35__py3-none-any.whl → 0.36__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.

@@ -24,14 +24,10 @@ from .utils.logger import LoggingRecord, logger
24
24
 
25
25
  # pylint: enable=wrong-import-position
26
26
 
27
- __version__ = 0.35
27
+ __version__ = 0.36
28
28
 
29
29
  _IMPORT_STRUCTURE = {
30
- "analyzer": [
31
- "config_sanity_checks",
32
- "get_dd_analyzer",
33
- "ServiceFactory"
34
- ],
30
+ "analyzer": ["config_sanity_checks", "get_dd_analyzer", "ServiceFactory"],
35
31
  "configs": [],
36
32
  "dataflow": [
37
33
  "DataFlowTerminated",
@@ -379,6 +375,7 @@ _IMPORT_STRUCTURE = {
379
375
  "get_pdf_file_writer",
380
376
  "PDFStreamer",
381
377
  "pdf_to_np_array",
378
+ "split_pdf",
382
379
  "ObjectTypes",
383
380
  "TypeOrStr",
384
381
  "object_types_registry",
@@ -17,11 +17,13 @@
17
17
 
18
18
  """Pipeline configuration for deepdoctection analyzer. Do not change the defaults in this file. """
19
19
 
20
+ from ..datapoint.view import IMAGE_DEFAULTS
20
21
  from ..utils.metacfg import AttrDict
21
22
  from ..utils.settings import CellType, LayoutType
22
23
 
23
24
  cfg = AttrDict()
24
25
 
26
+
25
27
  cfg.LANGUAGE = None
26
28
  cfg.LIB = None
27
29
  cfg.DEVICE = None
@@ -32,11 +34,9 @@ cfg.USE_TABLE_SEGMENTATION = True
32
34
  cfg.TF.LAYOUT.WEIGHTS = "layout/model-800000_inf_only.data-00000-of-00001"
33
35
  cfg.TF.LAYOUT.FILTER = None
34
36
 
35
-
36
37
  cfg.TF.CELL.WEIGHTS = "cell/model-1800000_inf_only.data-00000-of-00001"
37
38
  cfg.TF.CELL.FILTER = None
38
39
 
39
-
40
40
  cfg.TF.ITEM.WEIGHTS = "item/model-1620000_inf_only.data-00000-of-00001"
41
41
  cfg.TF.ITEM.FILTER = None
42
42
 
@@ -112,7 +112,7 @@ cfg.OCR.WEIGHTS.DOCTR_WORD.PT = "doctr/db_resnet50/pt/db_resnet50-ac60cadc.pt"
112
112
  cfg.OCR.WEIGHTS.DOCTR_RECOGNITION.TF = "doctr/crnn_vgg16_bn/tf/crnn_vgg16_bn-76b7f2c6.zip"
113
113
  cfg.OCR.WEIGHTS.DOCTR_RECOGNITION.PT = "doctr/crnn_vgg16_bn/pt/crnn_vgg16_bn-9762b0b0.pt"
114
114
 
115
- cfg.TEXT_CONTAINER = LayoutType.WORD
115
+ cfg.TEXT_CONTAINER = IMAGE_DEFAULTS["text_container"]
116
116
  cfg.WORD_MATCHING.PARENTAL_CATEGORIES = [
117
117
  LayoutType.TEXT,
118
118
  LayoutType.TITLE,
@@ -127,24 +127,16 @@ cfg.WORD_MATCHING.RULE = "ioa"
127
127
  cfg.WORD_MATCHING.THRESHOLD = 0.6
128
128
  cfg.WORD_MATCHING.MAX_PARENT_ONLY = True
129
129
 
130
- cfg.TEXT_ORDERING.TEXT_BLOCK_CATEGORIES = [
131
- LayoutType.TEXT,
132
- LayoutType.TITLE,
133
- LayoutType.LIST,
134
- LayoutType.CELL,
135
- CellType.COLUMN_HEADER,
136
- CellType.PROJECTED_ROW_HEADER,
137
- CellType.SPANNING,
138
- CellType.ROW_HEADER,
139
- ]
140
- cfg.TEXT_ORDERING.FLOATING_TEXT_BLOCK_CATEGORIES = [
141
- LayoutType.TEXT,
142
- LayoutType.TITLE,
143
- LayoutType.LIST,
144
- ]
130
+ cfg.TEXT_ORDERING.TEXT_BLOCK_CATEGORIES = IMAGE_DEFAULTS["text_block_categories"]
131
+ cfg.TEXT_ORDERING.FLOATING_TEXT_BLOCK_CATEGORIES = IMAGE_DEFAULTS["floating_text_block_categories"]
145
132
  cfg.TEXT_ORDERING.INCLUDE_RESIDUAL_TEXT_CONTAINER = False
146
133
  cfg.TEXT_ORDERING.STARTING_POINT_TOLERANCE = 0.005
147
134
  cfg.TEXT_ORDERING.BROKEN_LINE_TOLERANCE = 0.003
148
135
  cfg.TEXT_ORDERING.HEIGHT_TOLERANCE = 2.0
149
136
  cfg.TEXT_ORDERING.PARAGRAPH_BREAK = 0.035
137
+
138
+ cfg.USE_LAYOUT_LINK = False
139
+ cfg.LAYOUT_LINK.PARENTAL_CATEGORIES = []
140
+ cfg.LAYOUT_LINK.CHILD_CATEGORIES = []
141
+
150
142
  cfg.freeze()
@@ -33,7 +33,13 @@ from ..extern.tessocr import TesseractOcrDetector, TesseractRotationTransformer
33
33
  from ..extern.texocr import TextractOcrDetector
34
34
  from ..extern.tpdetect import TPFrcnnDetector
35
35
  from ..pipe.base import PipelineComponent
36
- from ..pipe.common import AnnotationNmsService, IntersectionMatcher, MatchingService, PageParsingService
36
+ from ..pipe.common import (
37
+ AnnotationNmsService,
38
+ IntersectionMatcher,
39
+ MatchingService,
40
+ NeighbourMatcher,
41
+ PageParsingService,
42
+ )
37
43
  from ..pipe.doctectionpipe import DoctectionPipe
38
44
  from ..pipe.layout import ImageLayoutService
39
45
  from ..pipe.order import TextOrderService
@@ -78,7 +84,7 @@ class ServiceFactory:
78
84
  """
79
85
 
80
86
  @staticmethod
81
- def build_layout_detector(
87
+ def _build_layout_detector(
82
88
  config: AttrDict,
83
89
  mode: str,
84
90
  ) -> Union[D2FrcnnDetector, TPFrcnnDetector, HFDetrDerivedDetector, D2FrcnnTracingDetector]:
@@ -141,17 +147,38 @@ class ServiceFactory:
141
147
  )
142
148
 
143
149
  @staticmethod
144
- def build_rotation_detector() -> TesseractRotationTransformer:
150
+ def build_layout_detector(
151
+ config: AttrDict, mode: str
152
+ ) -> Union[D2FrcnnDetector, TPFrcnnDetector, HFDetrDerivedDetector, D2FrcnnTracingDetector]:
153
+ """Building a layout detector according to the config
154
+
155
+ :param config: configuration object
156
+ :param mode: either `LAYOUT`,`CELL` or `ITEM`
157
+ """
158
+ return ServiceFactory._build_layout_detector(config, mode)
159
+
160
+ @staticmethod
161
+ def _build_rotation_detector() -> TesseractRotationTransformer:
145
162
  """Building a rotation detector"""
146
163
  return TesseractRotationTransformer()
147
164
 
148
165
  @staticmethod
149
- def build_transform_service(transform_predictor: ImageTransformer) -> SimpleTransformService:
166
+ def build_rotation_detector() -> TesseractRotationTransformer:
167
+ """Building a rotation detector"""
168
+ return ServiceFactory._build_rotation_detector()
169
+
170
+ @staticmethod
171
+ def _build_transform_service(transform_predictor: ImageTransformer) -> SimpleTransformService:
150
172
  """Building a transform service with a given predictor"""
151
173
  return SimpleTransformService(transform_predictor)
152
174
 
153
175
  @staticmethod
154
- def build_padder(config: AttrDict, mode: str) -> PadTransform:
176
+ def build_transform_service(transform_predictor: ImageTransformer) -> SimpleTransformService:
177
+ """Building a transform service with a given predictor"""
178
+ return ServiceFactory._build_transform_service(transform_predictor)
179
+
180
+ @staticmethod
181
+ def _build_padder(config: AttrDict, mode: str) -> PadTransform:
155
182
  """Building a padder according to the config
156
183
 
157
184
  :param config: configuration object
@@ -164,10 +191,20 @@ class ServiceFactory:
164
191
  getattr(config.PT, mode).PAD.BOTTOM,
165
192
  getattr(config.PT, mode).PAD.LEFT,
166
193
  )
167
- return PadTransform(top=top, right=right, bottom=bottom, left=left)
194
+ return PadTransform(top=top, right=right, bottom=bottom, left=left) #
168
195
 
169
196
  @staticmethod
170
- def build_layout_service(config: AttrDict, detector: ObjectDetector, mode: str) -> ImageLayoutService:
197
+ def build_padder(config: AttrDict, mode: str) -> PadTransform:
198
+ """Building a padder according to the config
199
+
200
+ :param config: configuration object
201
+ :param mode: either `LAYOUT`,`CELL` or `ITEM`
202
+ :return `PadTransform` instance
203
+ """
204
+ return ServiceFactory._build_padder(config, mode)
205
+
206
+ @staticmethod
207
+ def _build_layout_service(config: AttrDict, detector: ObjectDetector, mode: str) -> ImageLayoutService:
171
208
  """Building a layout service with a given detector
172
209
 
173
210
  :param config: configuration object
@@ -181,7 +218,18 @@ class ServiceFactory:
181
218
  return ImageLayoutService(layout_detector=detector, to_image=True, crop_image=True, padder=padder)
182
219
 
183
220
  @staticmethod
184
- def build_layout_nms_service(config: AttrDict) -> AnnotationNmsService:
221
+ def build_layout_service(config: AttrDict, detector: ObjectDetector, mode: str) -> ImageLayoutService:
222
+ """Building a layout service with a given detector
223
+
224
+ :param config: configuration object
225
+ :param detector: will be passed to the `ImageLayoutService`
226
+ :param mode: either `LAYOUT`,`CELL` or `ITEM`
227
+ :return `ImageLayoutService` instance
228
+ """
229
+ return ServiceFactory._build_layout_service(config, detector, mode)
230
+
231
+ @staticmethod
232
+ def _build_layout_nms_service(config: AttrDict) -> AnnotationNmsService:
185
233
  """Building a NMS service for layout annotations
186
234
 
187
235
  :param config: configuration object
@@ -199,7 +247,15 @@ class ServiceFactory:
199
247
  )
200
248
 
201
249
  @staticmethod
202
- def build_sub_image_service(config: AttrDict, detector: ObjectDetector, mode: str) -> SubImageLayoutService:
250
+ def build_layout_nms_service(config: AttrDict) -> AnnotationNmsService:
251
+ """Building a NMS service for layout annotations
252
+
253
+ :param config: configuration object
254
+ """
255
+ return ServiceFactory._build_layout_nms_service(config)
256
+
257
+ @staticmethod
258
+ def _build_sub_image_service(config: AttrDict, detector: ObjectDetector, mode: str) -> SubImageLayoutService:
203
259
  """
204
260
  Building a sub image layout service with a given detector
205
261
 
@@ -226,7 +282,19 @@ class ServiceFactory:
226
282
  )
227
283
 
228
284
  @staticmethod
229
- def build_ocr_detector(config: AttrDict) -> Union[TesseractOcrDetector, DoctrTextRecognizer, TextractOcrDetector]:
285
+ def build_sub_image_service(config: AttrDict, detector: ObjectDetector, mode: str) -> SubImageLayoutService:
286
+ """
287
+ Building a sub image layout service with a given detector
288
+
289
+ :param config: configuration object
290
+ :param detector: will be passed to the `SubImageLayoutService`
291
+ :param mode: either `LAYOUT`,`CELL` or `ITEM`
292
+ :return: `SubImageLayoutService` instance
293
+ """
294
+ return ServiceFactory._build_sub_image_service(config, detector, mode)
295
+
296
+ @staticmethod
297
+ def _build_ocr_detector(config: AttrDict) -> Union[TesseractOcrDetector, DoctrTextRecognizer, TextractOcrDetector]:
230
298
  """
231
299
  Building OCR predictor
232
300
 
@@ -266,6 +334,15 @@ class ServiceFactory:
266
334
  return TextractOcrDetector(**credentials_kwargs)
267
335
  raise ValueError("You have set USE_OCR=True but any of USE_TESSERACT, USE_DOCTR, USE_TEXTRACT is set to False")
268
336
 
337
+ @staticmethod
338
+ def build_ocr_detector(config: AttrDict) -> Union[TesseractOcrDetector, DoctrTextRecognizer, TextractOcrDetector]:
339
+ """
340
+ Building OCR predictor
341
+
342
+ :param config: configuration object
343
+ """
344
+ return ServiceFactory._build_ocr_detector(config)
345
+
269
346
  @staticmethod
270
347
  def build_doctr_word_detector(config: AttrDict) -> DoctrTextlineDetector:
271
348
  """Building `DoctrTextlineDetector` instance
@@ -285,7 +362,7 @@ class ServiceFactory:
285
362
  )
286
363
 
287
364
  @staticmethod
288
- def build_table_segmentation_service(
365
+ def _build_table_segmentation_service(
289
366
  config: AttrDict,
290
367
  detector: ObjectDetector,
291
368
  ) -> Union[PubtablesSegmentationService, TableSegmentationService]:
@@ -342,7 +419,32 @@ class ServiceFactory:
342
419
  return table_segmentation
343
420
 
344
421
  @staticmethod
345
- def build_table_refinement_service(config: AttrDict) -> TableSegmentationRefinementService:
422
+ def build_table_segmentation_service(
423
+ config: AttrDict,
424
+ detector: ObjectDetector,
425
+ ) -> Union[PubtablesSegmentationService, TableSegmentationService]:
426
+ """
427
+ Build and return a table segmentation service based on the provided detector.
428
+
429
+ Depending on the type of the detector, this method will return either a `PubtablesSegmentationService` or a
430
+ `TableSegmentationService` instance. The selection is made as follows:
431
+
432
+ - If the detector is an instance of `HFDetrDerivedDetector`, a `PubtablesSegmentationService` is created and
433
+ returned. This service uses specific configuration parameters for segmentation, such as assignment rules,
434
+ thresholds, and cell names defined in the `cfg` object.
435
+ - For other detector types, a `TableSegmentationService` is created and returned. This service also uses
436
+ configuration parameters from the `cfg` object but is tailored for different segmentation needs.
437
+
438
+ :param config: configuration object
439
+ :param detector: An instance of `ObjectDetector` used to determine the type of table segmentation
440
+ service to build.
441
+ :return: An instance of either `PubtablesSegmentationService` or `TableSegmentationService` based on the
442
+ detector type.
443
+ """
444
+ return ServiceFactory._build_table_segmentation_service(config, detector)
445
+
446
+ @staticmethod
447
+ def _build_table_refinement_service(config: AttrDict) -> TableSegmentationRefinementService:
346
448
  """Building a table segmentation refinement service
347
449
 
348
450
  :param config: configuration object
@@ -354,7 +456,16 @@ class ServiceFactory:
354
456
  )
355
457
 
356
458
  @staticmethod
357
- def build_pdf_text_detector(config: AttrDict) -> PdfPlumberTextDetector:
459
+ def build_table_refinement_service(config: AttrDict) -> TableSegmentationRefinementService:
460
+ """Building a table segmentation refinement service
461
+
462
+ :param config: configuration object
463
+ :return: TableSegmentationRefinementService
464
+ """
465
+ return ServiceFactory._build_table_refinement_service(config)
466
+
467
+ @staticmethod
468
+ def _build_pdf_text_detector(config: AttrDict) -> PdfPlumberTextDetector:
358
469
  """Building a PDF text detector
359
470
 
360
471
  :param config: configuration object
@@ -365,7 +476,16 @@ class ServiceFactory:
365
476
  )
366
477
 
367
478
  @staticmethod
368
- def build_pdf_miner_text_service(detector: PdfMiner) -> TextExtractionService:
479
+ def build_pdf_text_detector(config: AttrDict) -> PdfPlumberTextDetector:
480
+ """Building a PDF text detector
481
+
482
+ :param config: configuration object
483
+ :return: PdfPlumberTextDetector
484
+ """
485
+ return ServiceFactory._build_pdf_text_detector(config)
486
+
487
+ @staticmethod
488
+ def _build_pdf_miner_text_service(detector: PdfMiner) -> TextExtractionService:
369
489
  """Building a PDFMiner text extraction service
370
490
 
371
491
  :param detector: PdfMiner
@@ -373,6 +493,15 @@ class ServiceFactory:
373
493
  """
374
494
  return TextExtractionService(detector)
375
495
 
496
+ @staticmethod
497
+ def build_pdf_miner_text_service(detector: PdfMiner) -> TextExtractionService:
498
+ """Building a PDFMiner text extraction service
499
+
500
+ :param detector: PdfMiner
501
+ :return: TextExtractionService
502
+ """
503
+ return ServiceFactory._build_pdf_miner_text_service(detector)
504
+
376
505
  @staticmethod
377
506
  def build_doctr_word_detector_service(detector: DoctrTextlineDetector) -> ImageLayoutService:
378
507
  """Building a Doctr word detector service
@@ -385,7 +514,7 @@ class ServiceFactory:
385
514
  )
386
515
 
387
516
  @staticmethod
388
- def build_text_extraction_service(
517
+ def _build_text_extraction_service(
389
518
  config: AttrDict, detector: Union[TesseractOcrDetector, DoctrTextRecognizer, TextractOcrDetector]
390
519
  ) -> TextExtractionService:
391
520
  """Building a text extraction service
@@ -401,7 +530,19 @@ class ServiceFactory:
401
530
  )
402
531
 
403
532
  @staticmethod
404
- def build_word_matching_service(config: AttrDict) -> MatchingService:
533
+ def build_text_extraction_service(
534
+ config: AttrDict, detector: Union[TesseractOcrDetector, DoctrTextRecognizer, TextractOcrDetector]
535
+ ) -> TextExtractionService:
536
+ """Building a text extraction service
537
+
538
+ :param config: configuration object
539
+ :param detector: OCR detector
540
+ :return: TextExtractionService
541
+ """
542
+ return ServiceFactory._build_text_extraction_service(config, detector)
543
+
544
+ @staticmethod
545
+ def _build_word_matching_service(config: AttrDict) -> MatchingService:
405
546
  """Building a word matching service
406
547
 
407
548
  :param config: configuration object
@@ -420,7 +561,40 @@ class ServiceFactory:
420
561
  )
421
562
 
422
563
  @staticmethod
423
- def build_text_order_service(config: AttrDict) -> TextOrderService:
564
+ def build_word_matching_service(config: AttrDict) -> MatchingService:
565
+ """Building a word matching service
566
+
567
+ :param config: configuration object
568
+ :return: MatchingService
569
+ """
570
+ return ServiceFactory._build_word_matching_service(config)
571
+
572
+ @staticmethod
573
+ def _build_layout_link_matching_service(config: AttrDict) -> MatchingService:
574
+ """Building a word matching service
575
+
576
+ :param config: configuration object
577
+ :return: MatchingService
578
+ """
579
+ neighbor_matcher = NeighbourMatcher()
580
+ return MatchingService(
581
+ parent_categories=config.LAYOUT_LINK.PARENTAL_CATEGORIES,
582
+ child_categories=config.LAYOUT_LINK.CHILD_CATEGORIES,
583
+ matcher=neighbor_matcher,
584
+ relationship_key=Relationships.LAYOUT_LINK,
585
+ )
586
+
587
+ @staticmethod
588
+ def build_layout_link_matching_service(config: AttrDict) -> MatchingService:
589
+ """Building a word matching service
590
+
591
+ :param config: configuration object
592
+ :return: MatchingService
593
+ """
594
+ return ServiceFactory._build_layout_link_matching_service(config)
595
+
596
+ @staticmethod
597
+ def _build_text_order_service(config: AttrDict) -> TextOrderService:
424
598
  """Building a text order service
425
599
 
426
600
  :param config: configuration object
@@ -438,7 +612,16 @@ class ServiceFactory:
438
612
  )
439
613
 
440
614
  @staticmethod
441
- def build_page_parsing_service(config: AttrDict) -> PageParsingService:
615
+ def build_text_order_service(config: AttrDict) -> TextOrderService:
616
+ """Building a text order service
617
+
618
+ :param config: configuration object
619
+ :return: TextOrderService instance
620
+ """
621
+ return ServiceFactory._build_text_order_service(config)
622
+
623
+ @staticmethod
624
+ def _build_page_parsing_service(config: AttrDict) -> PageParsingService:
442
625
  """Building a page parsing service
443
626
 
444
627
  :param config: configuration object
@@ -450,6 +633,15 @@ class ServiceFactory:
450
633
  include_residual_text_container=config.TEXT_ORDERING.INCLUDE_RESIDUAL_TEXT_CONTAINER,
451
634
  )
452
635
 
636
+ @staticmethod
637
+ def build_page_parsing_service(config: AttrDict) -> PageParsingService:
638
+ """Building a page parsing service
639
+
640
+ :param config: configuration object
641
+ :return: PageParsingService instance
642
+ """
643
+ return ServiceFactory._build_page_parsing_service(config)
644
+
453
645
  @staticmethod
454
646
  def build_analyzer(config: AttrDict) -> DoctectionPipe:
455
647
  """
@@ -517,6 +709,10 @@ class ServiceFactory:
517
709
  text_order_service = ServiceFactory.build_text_order_service(config)
518
710
  pipe_component_list.append(text_order_service)
519
711
 
712
+ if config.USE_LAYOUT_LINK:
713
+ layout_link_matching_service = ServiceFactory.build_layout_link_matching_service(config)
714
+ pipe_component_list.append(layout_link_matching_service)
715
+
520
716
  page_parsing_service = ServiceFactory.build_page_parsing_service(config)
521
717
 
522
718
  return DoctectionPipe(pipeline_component_list=pipe_component_list, page_parsing_service=page_parsing_service)
@@ -98,3 +98,7 @@ TEXT_ORDERING:
98
98
  BROKEN_LINE_TOLERANCE: 0.003
99
99
  HEIGHT_TOLERANCE: 2.0
100
100
  PARAGRAPH_BREAK: 0.035
101
+ USE_LAYOUT_LINK: False
102
+ LAYOUT_LINK:
103
+ PARENTAL_CATEGORIES:
104
+ CHILD_CATEGORIES:
@@ -25,6 +25,7 @@ from copy import copy
25
25
  from typing import Any, Mapping, Optional, Sequence, Type, TypedDict, Union, no_type_check
26
26
 
27
27
  import numpy as np
28
+ from typing_extensions import LiteralString
28
29
 
29
30
  from ..utils.error import AnnotationError, ImageError
30
31
  from ..utils.logger import LoggingRecord, logger
@@ -40,10 +41,12 @@ from ..utils.settings import (
40
41
  WordType,
41
42
  get_type,
42
43
  )
44
+ from ..utils.transform import ResizeTransform
43
45
  from ..utils.types import HTML, AnnotationDict, Chunks, ImageDict, PathLikeOrStr, PixelValues, Text_, csv
44
46
  from ..utils.viz import draw_boxes, interactive_imshow, viz_handler
45
47
  from .annotation import CategoryAnnotation, ContainerAnnotation, ImageAnnotation, ann_from_dict
46
48
  from .box import BoundingBox, crop_box_from_image
49
+ from .convert import box_to_point4, point4_to_box
47
50
  from .image import Image
48
51
 
49
52
 
@@ -101,7 +104,7 @@ class ImageAnnotationBaseView(ImageAnnotation):
101
104
  return np_image
102
105
  raise AnnotationError(f"base_page.image is None for {self.annotation_id}")
103
106
 
104
- def __getattr__(self, item: str) -> Optional[Union[str, int, list[str]]]:
107
+ def __getattr__(self, item: str) -> Optional[Union[str, int, list[str], list[ImageAnnotationBaseView]]]:
105
108
  """
106
109
  Get attributes defined by registered `self.get_attribute_names()` in a multi step process:
107
110
 
@@ -126,6 +129,9 @@ class ImageAnnotationBaseView(ImageAnnotation):
126
129
  if isinstance(sub_cat, ContainerAnnotation):
127
130
  return sub_cat.value
128
131
  return sub_cat.category_id
132
+ if item in self.relationships:
133
+ relationship_ids = self.get_relationship(get_type(item))
134
+ return self.base_page.get_annotation(annotation_ids=relationship_ids)
129
135
  if self.image is not None:
130
136
  if item in self.image.summary.sub_categories:
131
137
  sub_cat = self.get_summary(get_type(item))
@@ -165,7 +171,11 @@ class Word(ImageAnnotationBaseView):
165
171
  """
166
172
 
167
173
  def get_attribute_names(self) -> set[str]:
168
- return set(WordType).union(super().get_attribute_names()).union({Relationships.READING_ORDER})
174
+ return (
175
+ set(WordType)
176
+ .union(super().get_attribute_names())
177
+ .union({Relationships.READING_ORDER, Relationships.LAYOUT_LINK})
178
+ )
169
179
 
170
180
 
171
181
  class Layout(ImageAnnotationBaseView):
@@ -246,7 +256,11 @@ class Layout(ImageAnnotationBaseView):
246
256
  }
247
257
 
248
258
  def get_attribute_names(self) -> set[str]:
249
- return {"words", "text"}.union(super().get_attribute_names()).union({Relationships.READING_ORDER})
259
+ return (
260
+ {"words", "text"}
261
+ .union(super().get_attribute_names())
262
+ .union({Relationships.READING_ORDER, Relationships.LAYOUT_LINK})
263
+ )
250
264
 
251
265
  def __len__(self) -> int:
252
266
  """len of text counted by number of characters"""
@@ -433,8 +447,8 @@ class ImageDefaults(TypedDict):
433
447
  """ImageDefaults"""
434
448
 
435
449
  text_container: LayoutType
436
- floating_text_block_categories: tuple[LayoutType, ...]
437
- text_block_categories: tuple[LayoutType, ...]
450
+ floating_text_block_categories: tuple[Union[LayoutType, CellType], ...]
451
+ text_block_categories: tuple[Union[LayoutType, CellType], ...]
438
452
 
439
453
 
440
454
  IMAGE_DEFAULTS: ImageDefaults = {
@@ -448,9 +462,13 @@ IMAGE_DEFAULTS: ImageDefaults = {
448
462
  "text_block_categories": (
449
463
  LayoutType.TEXT,
450
464
  LayoutType.TITLE,
451
- LayoutType.FIGURE,
452
465
  LayoutType.LIST,
453
466
  LayoutType.CELL,
467
+ LayoutType.FIGURE,
468
+ CellType.COLUMN_HEADER,
469
+ CellType.PROJECTED_ROW_HEADER,
470
+ CellType.SPANNING,
471
+ CellType.ROW_HEADER,
454
472
  ),
455
473
  }
456
474
 
@@ -510,6 +528,8 @@ class Page(Image):
510
528
  "document_id",
511
529
  "page_number",
512
530
  "angle",
531
+ "figures",
532
+ "residual_layouts",
513
533
  }
514
534
  include_residual_text_container: bool = True
515
535
 
@@ -608,6 +628,41 @@ class Page(Image):
608
628
  """
609
629
  return self.get_annotation(category_names=LayoutType.TABLE)
610
630
 
631
+ @property
632
+ def figures(self) -> list[ImageAnnotationBaseView]:
633
+ """
634
+ A list of a figures.
635
+ """
636
+ return self.get_annotation(category_names=LayoutType.FIGURE)
637
+
638
+ @property
639
+ def residual_layouts(self) -> list[ImageAnnotationBaseView]:
640
+ """
641
+ A list of all residual layouts. Residual layouts are all layouts that are
642
+ - not floating text blocks,
643
+ - not text containers,
644
+ - not tables,
645
+ - not figures
646
+ - not cells
647
+ - not rows
648
+ - not columns
649
+ """
650
+ return self.get_annotation(category_names=self._get_residual_layout())
651
+
652
+ def _get_residual_layout(self) -> list[LiteralString]:
653
+ layouts = copy(list(self.floating_text_block_categories))
654
+ layouts.extend(
655
+ [
656
+ LayoutType.TABLE,
657
+ LayoutType.FIGURE,
658
+ self.text_container,
659
+ LayoutType.CELL,
660
+ LayoutType.ROW,
661
+ LayoutType.COLUMN,
662
+ ]
663
+ )
664
+ return [layout for layout in LayoutType if layout not in layouts]
665
+
611
666
  @classmethod
612
667
  def from_image(
613
668
  cls,
@@ -801,12 +856,15 @@ class Page(Image):
801
856
  self,
802
857
  show_tables: bool = True,
803
858
  show_layouts: bool = True,
859
+ show_figures: bool = False,
860
+ show_residual_layouts: bool = False,
804
861
  show_cells: bool = True,
805
862
  show_table_structure: bool = True,
806
863
  show_words: bool = False,
807
864
  show_token_class: bool = True,
808
865
  ignore_default_token_class: bool = False,
809
866
  interactive: bool = False,
867
+ scaled_width: int = 600,
810
868
  **debug_kwargs: str,
811
869
  ) -> Optional[PixelValues]:
812
870
  """
@@ -827,12 +885,14 @@ class Page(Image):
827
885
 
828
886
  :param show_tables: Will display all tables boxes as well as cells, rows and columns
829
887
  :param show_layouts: Will display all other layout components.
888
+ :param show_figures: Will display all figures
830
889
  :param show_cells: Will display cells within tables. (Only available if `show_tables=True`)
831
890
  :param show_table_structure: Will display rows and columns
832
891
  :param show_words: Will display bounding boxes around words labeled with token class and bio tag (experimental)
833
892
  :param show_token_class: Will display token class instead of token tags (i.e. token classes with tags)
834
893
  :param interactive: If set to True will open an interactive image, otherwise it will return a numpy array that
835
894
  can be displayed differently.
895
+ :param scaled_width: Width of the image to display
836
896
  :param ignore_default_token_class: Will ignore displaying word bounding boxes with default or None token class
837
897
  label
838
898
  :return: If `interactive=False` will return a numpy array.
@@ -858,6 +918,11 @@ class Page(Image):
858
918
  box_stack.append(item.bbox)
859
919
  category_names_list.append(item.category_name.value)
860
920
 
921
+ if show_figures and not debug_kwargs:
922
+ for item in self.figures:
923
+ box_stack.append(item.bbox)
924
+ category_names_list.append(item.category_name.value)
925
+
861
926
  if show_tables and not debug_kwargs:
862
927
  for table in self.tables:
863
928
  box_stack.append(table.bbox)
@@ -914,24 +979,34 @@ class Page(Image):
914
979
  else:
915
980
  category_names_list.append(word.token_tag.value if word.token_tag is not None else None)
916
981
 
982
+ if show_residual_layouts and not debug_kwargs:
983
+ for item in self.residual_layouts:
984
+ box_stack.append(item.bbox)
985
+ category_names_list.append(item.category_name.value)
986
+
917
987
  if self.image is not None:
988
+ scale_fx = scaled_width / self.width
989
+ scaled_height = int(self.height * scale_fx)
990
+ img = viz_handler.resize(self.image, scaled_width, scaled_height, "VIZ")
991
+
918
992
  if box_stack:
919
993
  boxes = np.vstack(box_stack)
994
+ boxes = box_to_point4(boxes)
995
+ resizer = ResizeTransform(self.height, self.width, scaled_height, scaled_width, "VIZ")
996
+ boxes = resizer.apply_coords(boxes)
997
+ boxes = point4_to_box(boxes)
920
998
  if show_words:
921
999
  img = draw_boxes(
922
- self.image,
923
- boxes,
924
- category_names_list,
1000
+ np_image=img,
1001
+ boxes=boxes,
1002
+ category_names_list=category_names_list,
925
1003
  font_scale=1.0,
926
1004
  rectangle_thickness=4,
927
1005
  )
928
1006
  else:
929
- img = draw_boxes(self.image, boxes, category_names_list)
930
- scale_fx, scale_fy = 1.3, 1.3
931
- scaled_width, scaled_height = int(self.width * scale_fx), int(self.height * scale_fy)
932
- img = viz_handler.resize(img, scaled_width, scaled_height, "VIZ")
933
- else:
934
- img = self.image
1007
+ img = draw_boxes(
1008
+ np_image=img, boxes=boxes, category_names_list=category_names_list, show_palette=False
1009
+ )
935
1010
 
936
1011
  if interactive:
937
1012
  interactive_imshow(img)
@@ -71,8 +71,8 @@ https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocotools/cocoeva
71
71
 
72
72
 
73
73
  def _summarize( # type: ignore
74
- self, ap: int = 1, iouThr: float = 0.9, areaRng: str = "all", maxDets: int = 100
75
- ) -> float:
74
+ self, ap: int = 1, iouThr: float = 0.9, areaRng: str = "all", maxDets: int = 100, per_category: bool = False
75
+ ) -> Union[float, list[float]]:
76
76
  # pylint: disable=C0103
77
77
  p = self.params
78
78
  iStr = " {:<18} {} @[ IoU={:<9} | area={:>6s} | maxDets={:>3d} ] = {:0.3f}"
@@ -86,6 +86,36 @@ def _summarize( # type: ignore
86
86
 
87
87
  aind = [i for i, aRng in enumerate(p.areaRngLbl) if aRng == areaRng]
88
88
  mind = [i for i, mDet in enumerate(p.maxDets) if mDet == maxDets]
89
+ if per_category:
90
+ if ap == 1:
91
+ s = self.eval["precision"]
92
+ num_classes = s.shape[2]
93
+ results_per_class = []
94
+ for idx in range(num_classes):
95
+ if iouThr is not None:
96
+ s = self.eval["precision"]
97
+ t = np.where(iouThr == p.iouThrs)[0]
98
+ s = s[t]
99
+ precision = s[:, :, idx, aind, mind]
100
+ precision = precision[precision > -1]
101
+ res = np.mean(precision) if precision.size else float("nan")
102
+ results_per_class.append(float(res))
103
+ print(f"Precision for class {idx+1}: @[ IoU={iouStr} | area={areaRng} | maxDets={maxDets} ] = {res}")
104
+ else:
105
+ s = self.eval["recall"]
106
+ num_classes = s.shape[1]
107
+ results_per_class = []
108
+ for idx in range(num_classes):
109
+ if iouThr is not None:
110
+ s = self.eval["recall"]
111
+ t = np.where(iouThr == p.iouThrs)[0]
112
+ s = s[t]
113
+ recall = s[:, idx, aind, mind]
114
+ recall = recall[recall > -1]
115
+ res = np.mean(recall) if recall.size else float("nan")
116
+ results_per_class.append(float(res))
117
+ print(f"Recall for class {idx+1}: @[ IoU={iouStr} | area={areaRng} | maxDets={maxDets} ] = {res}")
118
+ return results_per_class
89
119
  if ap == 1:
90
120
  # dimension of precision: [TxRxKxAxM]
91
121
  s = self.eval["precision"]
@@ -124,6 +154,7 @@ class CocoMetric(MetricBase):
124
154
  mapper = image_to_coco
125
155
  _f1_score = None
126
156
  _f1_iou = None
157
+ _per_category = False
127
158
  _params: dict[str, Union[list[int], list[list[int]]]] = {}
128
159
 
129
160
  @classmethod
@@ -176,18 +207,28 @@ class CocoMetric(MetricBase):
176
207
 
177
208
  if cls._f1_score:
178
209
  summary_bbox = [
179
- metric.summarize_f1(1, cls._f1_iou, maxDets=metric.params.maxDets[2]),
180
- metric.summarize_f1(0, cls._f1_iou, maxDets=metric.params.maxDets[2]),
210
+ metric.summarize_f1(1, cls._f1_iou, maxDets=metric.params.maxDets[2], per_category=cls._per_category),
211
+ metric.summarize_f1(0, cls._f1_iou, maxDets=metric.params.maxDets[2], per_category=cls._per_category),
181
212
  ]
182
213
  else:
183
214
  metric.summarize()
184
215
  summary_bbox = metric.stats
185
216
 
186
217
  results = []
187
- for params, value in zip(cls.get_summary_default_parameters(), summary_bbox):
218
+
219
+ default_parameters = cls.get_summary_default_parameters()
220
+ if cls._per_category:
221
+ default_parameters = default_parameters * len(summary_bbox[0])
222
+ summary_bbox = [item for pair in zip(*summary_bbox) for item in pair]
223
+ val = 0
224
+ for idx, (params, value) in enumerate(zip(default_parameters, summary_bbox)):
188
225
  params = copy(params)
189
226
  params["mode"] = "bbox"
190
227
  params["val"] = value
228
+ if cls._per_category:
229
+ if idx % 2 == 0:
230
+ val += 1
231
+ params["category_id"] = val
191
232
  results.append(params)
192
233
 
193
234
  return results
@@ -201,15 +242,16 @@ class CocoMetric(MetricBase):
201
242
  area range and maximum detections.
202
243
  """
203
244
  if cls._f1_score:
245
+ for el, idx in zip(_F1_DEFAULTS, [2, 2]):
246
+ if cls._params:
247
+ if cls._params.get("maxDets") is not None:
248
+ el["maxDets"] = cls._params["maxDets"][idx]
249
+ el["iouThr"] = cls._f1_iou
250
+ return _F1_DEFAULTS
251
+
252
+ for el, idx in zip(_COCOEVAL_DEFAULTS, _MAX_DET_INDEX):
204
253
  if cls._params:
205
254
  if cls._params.get("maxDets") is not None:
206
- for el, idx in zip(_F1_DEFAULTS, [2, 2]):
207
- el["maxDets"] = cls._params["maxDets"][idx]
208
- el["iouThr"] = cls._f1_iou
209
- return _F1_DEFAULTS
210
- if cls._params:
211
- if cls._params.get("maxDets") is not None:
212
- for el, idx in zip(_COCOEVAL_DEFAULTS, _MAX_DET_INDEX):
213
255
  el["maxDets"] = cls._params["maxDets"][idx]
214
256
  return _COCOEVAL_DEFAULTS
215
257
 
@@ -220,13 +262,16 @@ class CocoMetric(MetricBase):
220
262
  area_range: Optional[list[list[int]]] = None,
221
263
  f1_score: bool = False,
222
264
  f1_iou: float = 0.9,
265
+ per_category: bool = False,
223
266
  ) -> None:
224
267
  """
225
268
  Setting params for different coco metric modes.
226
269
 
227
270
  :param max_detections: The maximum number of detections to consider
228
271
  :param area_range: The area range to classify objects as "all", "small", "medium" and "large"
229
- :param f1_score: Will use f1 score setting with default iouThr 0.9
272
+ :param f1_score: Will use f1 score setting with default iouThr 0.9. To be more precise it does not calculate
273
+ the f1 score but the precision and recall for a given iou threshold. Use the harmonic mean to
274
+ get the ultimate f1 score.
230
275
  :param f1_iou: Use with f1_score True and reset the f1 iou threshold
231
276
  """
232
277
  if max_detections is not None:
@@ -238,6 +283,7 @@ class CocoMetric(MetricBase):
238
283
 
239
284
  cls._f1_score = f1_score
240
285
  cls._f1_iou = f1_iou
286
+ cls._per_category = per_category
241
287
 
242
288
  @classmethod
243
289
  def get_requirements(cls) -> list[Requirement]:
@@ -193,5 +193,7 @@ def match_anns_by_distance(
193
193
  child_anns = dp.get_annotation(annotation_ids=child_ann_ids, category_names=child_ann_category_names)
194
194
  child_centers = [block.get_bounding_box(dp.image_id).center for block in child_anns]
195
195
  parent_centers = [block.get_bounding_box(dp.image_id).center for block in parent_anns]
196
- child_indices = distance.cdist(parent_centers, child_centers).argmin(axis=1)
197
- return [(parent_anns[i], child_anns[j]) for i, j in enumerate(child_indices)]
196
+ if child_centers and parent_centers:
197
+ child_indices = distance.cdist(parent_centers, child_centers).argmin(axis=1)
198
+ return [(parent_anns[i], child_anns[j]) for i, j in enumerate(child_indices)]
199
+ return []
@@ -155,3 +155,42 @@ def is_file_extension(file_name: PathLikeOrStr, extension: Union[str, Sequence[s
155
155
  if isinstance(extension, str):
156
156
  return os.path.splitext(file_name)[-1].lower() == extension
157
157
  return os.path.splitext(file_name)[-1].lower() in extension
158
+
159
+
160
+ def partition_list(base_list: list[str], stop_value: str) -> list[list[str]]:
161
+ """
162
+ Partitions a list of strings into sublists, where each sublist starts with the first occurrence of the stop value.
163
+ Consecutive stop values are grouped together in the same sublist.
164
+
165
+ :param base_list: The list of strings to be partitioned.
166
+ :param stop_value: The string value that indicates the start of a new partition.
167
+ :return: A list of lists, where each sublist is a partition of the original list.
168
+
169
+ ** Example:**
170
+
171
+ strings = ['a', 'a', 'c', 'c', 'b', 'd', 'c', 'c', 'a', 'b', 'a', 'b', 'a', 'a']
172
+ stop_string = 'a'
173
+ partition_list(strings, stop_string)
174
+
175
+ # Output [['a', 'a', 'c', 'c', 'b', 'd', 'c', 'c'], ['a', 'b'], ['a', 'b'], ['a', 'a']]
176
+ """
177
+
178
+ partitions = []
179
+ current_partition: list[str] = []
180
+ stop_found = False
181
+
182
+ for s in base_list:
183
+ if s == stop_value:
184
+ if not stop_found and current_partition:
185
+ partitions.append(current_partition)
186
+ current_partition = []
187
+ current_partition.append(s)
188
+ stop_found = True
189
+ else:
190
+ current_partition.append(s)
191
+ stop_found = False
192
+
193
+ if current_partition:
194
+ partitions.append(current_partition)
195
+
196
+ return partitions
@@ -205,6 +205,7 @@ def draw_boxes(
205
205
  font_scale: float = 1.0,
206
206
  rectangle_thickness: int = 4,
207
207
  box_color_by_category: bool = True,
208
+ show_palette: bool = True,
208
209
  ) -> PixelValues:
209
210
  """
210
211
  Dray bounding boxes with category names into image.
@@ -216,6 +217,7 @@ def draw_boxes(
216
217
  :param font_scale: Font scale of text box
217
218
  :param rectangle_thickness: Thickness of bounding box
218
219
  :param box_color_by_category:
220
+ :param show_palette: Whether to show a color palette of the categories
219
221
  :return: A new image np.ndarray
220
222
  """
221
223
  if color is not None:
@@ -261,19 +263,20 @@ def draw_boxes(
261
263
  )
262
264
 
263
265
  # draw a (very ugly) color palette
264
- y_0 = np_image.shape[0]
265
- for category, col in category_to_color.items():
266
- if category is not None:
267
- np_image = viz_handler.draw_text(
268
- np_image,
269
- (np_image.shape[1], y_0),
270
- category,
271
- color=col,
272
- font_scale=font_scale * 3,
273
- rectangle_thickness=rectangle_thickness,
274
- )
275
- _, text_h = viz_handler.get_text_size(category, font_scale * 2)
276
- y_0 = y_0 - int(10 * text_h)
266
+ if show_palette:
267
+ y_0 = np_image.shape[0]
268
+ for category, col in category_to_color.items():
269
+ if category is not None:
270
+ np_image = viz_handler.draw_text(
271
+ np_image,
272
+ (np_image.shape[1], y_0),
273
+ category,
274
+ color=col,
275
+ font_scale=font_scale,
276
+ rectangle_thickness=rectangle_thickness,
277
+ )
278
+ _, text_h = viz_handler.get_text_size(category, font_scale * 2)
279
+ y_0 = y_0 - int(1 * text_h)
277
280
 
278
281
  return np_image
279
282
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepdoctection
3
- Version: 0.35
3
+ Version: 0.36
4
4
  Summary: Repository for Document AI
5
5
  Home-page: https://github.com/deepdoctection/deepdoctection
6
6
  Author: Dr. Janis Meyer
@@ -16,117 +16,117 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
16
  Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: catalogue ==2.0.10
20
- Requires-Dist: huggingface-hub <0.26,>=0.12.0
21
- Requires-Dist: importlib-metadata >=5.0.0
22
- Requires-Dist: jsonlines ==3.1.0
23
- Requires-Dist: lazy-imports ==0.3.1
24
- Requires-Dist: mock ==4.0.3
25
- Requires-Dist: networkx >=2.7.1
26
- Requires-Dist: numpy <2.0,>=1.21
27
- Requires-Dist: packaging >=20.0
28
- Requires-Dist: Pillow >=10.0.0
29
- Requires-Dist: pypdf >=3.16.0
30
- Requires-Dist: pypdfium2 >=4.30.0
31
- Requires-Dist: pyyaml >=6.0.1
32
- Requires-Dist: pyzmq >=16
33
- Requires-Dist: scipy >=1.13.1
34
- Requires-Dist: termcolor >=1.1
35
- Requires-Dist: tabulate >=0.7.7
36
- Requires-Dist: tqdm ==4.64.0
37
- Provides-Extra: dev
38
- Requires-Dist: python-dotenv ==1.0.0 ; extra == 'dev'
39
- Requires-Dist: click ; extra == 'dev'
40
- Requires-Dist: black ==23.7.0 ; extra == 'dev'
41
- Requires-Dist: isort ==5.13.2 ; extra == 'dev'
42
- Requires-Dist: pylint ==2.17.4 ; extra == 'dev'
43
- Requires-Dist: mypy ==1.4.1 ; extra == 'dev'
44
- Requires-Dist: wandb ; extra == 'dev'
45
- Requires-Dist: types-PyYAML >=6.0.12.12 ; extra == 'dev'
46
- Requires-Dist: types-termcolor >=1.1.3 ; extra == 'dev'
47
- Requires-Dist: types-tabulate >=0.9.0.3 ; extra == 'dev'
48
- Requires-Dist: types-tqdm >=4.66.0.5 ; extra == 'dev'
49
- Requires-Dist: lxml-stubs >=0.5.1 ; extra == 'dev'
50
- Requires-Dist: types-Pillow >=10.2.0.20240406 ; extra == 'dev'
51
- Requires-Dist: types-urllib3 >=1.26.25.14 ; extra == 'dev'
52
- Provides-Extra: docs
53
- Requires-Dist: tensorpack ==0.11 ; extra == 'docs'
54
- Requires-Dist: boto3 ==1.34.102 ; extra == 'docs'
55
- Requires-Dist: transformers >=4.36.0 ; extra == 'docs'
56
- Requires-Dist: accelerate >=0.29.1 ; extra == 'docs'
57
- Requires-Dist: pdfplumber >=0.11.0 ; extra == 'docs'
58
- Requires-Dist: lxml >=4.9.1 ; extra == 'docs'
59
- Requires-Dist: lxml-stubs >=0.5.1 ; extra == 'docs'
60
- Requires-Dist: jdeskew >=0.2.2 ; extra == 'docs'
61
- Requires-Dist: jinja2 ==3.0.3 ; extra == 'docs'
62
- Requires-Dist: mkdocs-material ; extra == 'docs'
63
- Requires-Dist: mkdocstrings-python ; extra == 'docs'
64
- Requires-Dist: griffe ==0.25.0 ; extra == 'docs'
19
+ Requires-Dist: catalogue==2.0.10
20
+ Requires-Dist: huggingface_hub<0.26,>=0.12.0
21
+ Requires-Dist: importlib-metadata>=5.0.0
22
+ Requires-Dist: jsonlines==3.1.0
23
+ Requires-Dist: lazy-imports==0.3.1
24
+ Requires-Dist: mock==4.0.3
25
+ Requires-Dist: networkx>=2.7.1
26
+ Requires-Dist: numpy<2.0,>=1.21
27
+ Requires-Dist: packaging>=20.0
28
+ Requires-Dist: Pillow>=10.0.0
29
+ Requires-Dist: pypdf>=3.16.0
30
+ Requires-Dist: pypdfium2>=4.30.0
31
+ Requires-Dist: pyyaml>=6.0.1
32
+ Requires-Dist: pyzmq>=16
33
+ Requires-Dist: scipy>=1.13.1
34
+ Requires-Dist: termcolor>=1.1
35
+ Requires-Dist: tabulate>=0.7.7
36
+ Requires-Dist: tqdm==4.64.0
37
+ Provides-Extra: tf
38
+ Requires-Dist: catalogue==2.0.10; extra == "tf"
39
+ Requires-Dist: huggingface_hub<0.26,>=0.12.0; extra == "tf"
40
+ Requires-Dist: importlib-metadata>=5.0.0; extra == "tf"
41
+ Requires-Dist: jsonlines==3.1.0; extra == "tf"
42
+ Requires-Dist: lazy-imports==0.3.1; extra == "tf"
43
+ Requires-Dist: mock==4.0.3; extra == "tf"
44
+ Requires-Dist: networkx>=2.7.1; extra == "tf"
45
+ Requires-Dist: numpy<2.0,>=1.21; extra == "tf"
46
+ Requires-Dist: packaging>=20.0; extra == "tf"
47
+ Requires-Dist: Pillow>=10.0.0; extra == "tf"
48
+ Requires-Dist: pypdf>=3.16.0; extra == "tf"
49
+ Requires-Dist: pypdfium2>=4.30.0; extra == "tf"
50
+ Requires-Dist: pyyaml>=6.0.1; extra == "tf"
51
+ Requires-Dist: pyzmq>=16; extra == "tf"
52
+ Requires-Dist: scipy>=1.13.1; extra == "tf"
53
+ Requires-Dist: termcolor>=1.1; extra == "tf"
54
+ Requires-Dist: tabulate>=0.7.7; extra == "tf"
55
+ Requires-Dist: tqdm==4.64.0; extra == "tf"
56
+ Requires-Dist: tensorpack==0.11; extra == "tf"
57
+ Requires-Dist: protobuf==3.20.1; extra == "tf"
58
+ Requires-Dist: tensorflow-addons>=0.17.1; extra == "tf"
59
+ Requires-Dist: tf2onnx>=1.9.2; extra == "tf"
60
+ Requires-Dist: python-doctr==0.8.1; extra == "tf"
61
+ Requires-Dist: pycocotools>=2.0.2; extra == "tf"
62
+ Requires-Dist: boto3==1.34.102; extra == "tf"
63
+ Requires-Dist: pdfplumber>=0.11.0; extra == "tf"
64
+ Requires-Dist: fasttext==0.9.2; extra == "tf"
65
+ Requires-Dist: jdeskew>=0.2.2; extra == "tf"
66
+ Requires-Dist: apted==1.0.3; extra == "tf"
67
+ Requires-Dist: distance==0.1.3; extra == "tf"
68
+ Requires-Dist: lxml>=4.9.1; extra == "tf"
65
69
  Provides-Extra: pt
66
- Requires-Dist: catalogue ==2.0.10 ; extra == 'pt'
67
- Requires-Dist: huggingface-hub <0.26,>=0.12.0 ; extra == 'pt'
68
- Requires-Dist: importlib-metadata >=5.0.0 ; extra == 'pt'
69
- Requires-Dist: jsonlines ==3.1.0 ; extra == 'pt'
70
- Requires-Dist: lazy-imports ==0.3.1 ; extra == 'pt'
71
- Requires-Dist: mock ==4.0.3 ; extra == 'pt'
72
- Requires-Dist: networkx >=2.7.1 ; extra == 'pt'
73
- Requires-Dist: numpy <2.0,>=1.21 ; extra == 'pt'
74
- Requires-Dist: packaging >=20.0 ; extra == 'pt'
75
- Requires-Dist: Pillow >=10.0.0 ; extra == 'pt'
76
- Requires-Dist: pypdf >=3.16.0 ; extra == 'pt'
77
- Requires-Dist: pypdfium2 >=4.30.0 ; extra == 'pt'
78
- Requires-Dist: pyyaml >=6.0.1 ; extra == 'pt'
79
- Requires-Dist: pyzmq >=16 ; extra == 'pt'
80
- Requires-Dist: scipy >=1.13.1 ; extra == 'pt'
81
- Requires-Dist: termcolor >=1.1 ; extra == 'pt'
82
- Requires-Dist: tabulate >=0.7.7 ; extra == 'pt'
83
- Requires-Dist: tqdm ==4.64.0 ; extra == 'pt'
84
- Requires-Dist: timm >=0.9.16 ; extra == 'pt'
85
- Requires-Dist: transformers >=4.36.0 ; extra == 'pt'
86
- Requires-Dist: accelerate >=0.29.1 ; extra == 'pt'
87
- Requires-Dist: python-doctr ==0.8.1 ; extra == 'pt'
88
- Requires-Dist: boto3 ==1.34.102 ; extra == 'pt'
89
- Requires-Dist: pdfplumber >=0.11.0 ; extra == 'pt'
90
- Requires-Dist: fasttext ==0.9.2 ; extra == 'pt'
91
- Requires-Dist: jdeskew >=0.2.2 ; extra == 'pt'
92
- Requires-Dist: apted ==1.0.3 ; extra == 'pt'
93
- Requires-Dist: distance ==0.1.3 ; extra == 'pt'
94
- Requires-Dist: lxml >=4.9.1 ; extra == 'pt'
70
+ Requires-Dist: catalogue==2.0.10; extra == "pt"
71
+ Requires-Dist: huggingface_hub<0.26,>=0.12.0; extra == "pt"
72
+ Requires-Dist: importlib-metadata>=5.0.0; extra == "pt"
73
+ Requires-Dist: jsonlines==3.1.0; extra == "pt"
74
+ Requires-Dist: lazy-imports==0.3.1; extra == "pt"
75
+ Requires-Dist: mock==4.0.3; extra == "pt"
76
+ Requires-Dist: networkx>=2.7.1; extra == "pt"
77
+ Requires-Dist: numpy<2.0,>=1.21; extra == "pt"
78
+ Requires-Dist: packaging>=20.0; extra == "pt"
79
+ Requires-Dist: Pillow>=10.0.0; extra == "pt"
80
+ Requires-Dist: pypdf>=3.16.0; extra == "pt"
81
+ Requires-Dist: pypdfium2>=4.30.0; extra == "pt"
82
+ Requires-Dist: pyyaml>=6.0.1; extra == "pt"
83
+ Requires-Dist: pyzmq>=16; extra == "pt"
84
+ Requires-Dist: scipy>=1.13.1; extra == "pt"
85
+ Requires-Dist: termcolor>=1.1; extra == "pt"
86
+ Requires-Dist: tabulate>=0.7.7; extra == "pt"
87
+ Requires-Dist: tqdm==4.64.0; extra == "pt"
88
+ Requires-Dist: timm>=0.9.16; extra == "pt"
89
+ Requires-Dist: transformers>=4.36.0; extra == "pt"
90
+ Requires-Dist: accelerate>=0.29.1; extra == "pt"
91
+ Requires-Dist: python-doctr==0.8.1; extra == "pt"
92
+ Requires-Dist: boto3==1.34.102; extra == "pt"
93
+ Requires-Dist: pdfplumber>=0.11.0; extra == "pt"
94
+ Requires-Dist: fasttext==0.9.2; extra == "pt"
95
+ Requires-Dist: jdeskew>=0.2.2; extra == "pt"
96
+ Requires-Dist: apted==1.0.3; extra == "pt"
97
+ Requires-Dist: distance==0.1.3; extra == "pt"
98
+ Requires-Dist: lxml>=4.9.1; extra == "pt"
99
+ Provides-Extra: docs
100
+ Requires-Dist: tensorpack==0.11; extra == "docs"
101
+ Requires-Dist: boto3==1.34.102; extra == "docs"
102
+ Requires-Dist: transformers>=4.36.0; extra == "docs"
103
+ Requires-Dist: accelerate>=0.29.1; extra == "docs"
104
+ Requires-Dist: pdfplumber>=0.11.0; extra == "docs"
105
+ Requires-Dist: lxml>=4.9.1; extra == "docs"
106
+ Requires-Dist: lxml-stubs>=0.5.1; extra == "docs"
107
+ Requires-Dist: jdeskew>=0.2.2; extra == "docs"
108
+ Requires-Dist: jinja2==3.0.3; extra == "docs"
109
+ Requires-Dist: mkdocs-material; extra == "docs"
110
+ Requires-Dist: mkdocstrings-python; extra == "docs"
111
+ Requires-Dist: griffe==0.25.0; extra == "docs"
112
+ Provides-Extra: dev
113
+ Requires-Dist: python-dotenv==1.0.0; extra == "dev"
114
+ Requires-Dist: click; extra == "dev"
115
+ Requires-Dist: black==23.7.0; extra == "dev"
116
+ Requires-Dist: isort==5.13.2; extra == "dev"
117
+ Requires-Dist: pylint==2.17.4; extra == "dev"
118
+ Requires-Dist: mypy==1.4.1; extra == "dev"
119
+ Requires-Dist: wandb; extra == "dev"
120
+ Requires-Dist: types-PyYAML>=6.0.12.12; extra == "dev"
121
+ Requires-Dist: types-termcolor>=1.1.3; extra == "dev"
122
+ Requires-Dist: types-tabulate>=0.9.0.3; extra == "dev"
123
+ Requires-Dist: types-tqdm>=4.66.0.5; extra == "dev"
124
+ Requires-Dist: lxml-stubs>=0.5.1; extra == "dev"
125
+ Requires-Dist: types-Pillow>=10.2.0.20240406; extra == "dev"
126
+ Requires-Dist: types-urllib3>=1.26.25.14; extra == "dev"
95
127
  Provides-Extra: test
96
- Requires-Dist: pytest ==8.0.2 ; extra == 'test'
97
- Requires-Dist: pytest-cov ; extra == 'test'
98
- Provides-Extra: tf
99
- Requires-Dist: catalogue ==2.0.10 ; extra == 'tf'
100
- Requires-Dist: huggingface-hub <0.26,>=0.12.0 ; extra == 'tf'
101
- Requires-Dist: importlib-metadata >=5.0.0 ; extra == 'tf'
102
- Requires-Dist: jsonlines ==3.1.0 ; extra == 'tf'
103
- Requires-Dist: lazy-imports ==0.3.1 ; extra == 'tf'
104
- Requires-Dist: mock ==4.0.3 ; extra == 'tf'
105
- Requires-Dist: networkx >=2.7.1 ; extra == 'tf'
106
- Requires-Dist: numpy <2.0,>=1.21 ; extra == 'tf'
107
- Requires-Dist: packaging >=20.0 ; extra == 'tf'
108
- Requires-Dist: Pillow >=10.0.0 ; extra == 'tf'
109
- Requires-Dist: pypdf >=3.16.0 ; extra == 'tf'
110
- Requires-Dist: pypdfium2 >=4.30.0 ; extra == 'tf'
111
- Requires-Dist: pyyaml >=6.0.1 ; extra == 'tf'
112
- Requires-Dist: pyzmq >=16 ; extra == 'tf'
113
- Requires-Dist: scipy >=1.13.1 ; extra == 'tf'
114
- Requires-Dist: termcolor >=1.1 ; extra == 'tf'
115
- Requires-Dist: tabulate >=0.7.7 ; extra == 'tf'
116
- Requires-Dist: tqdm ==4.64.0 ; extra == 'tf'
117
- Requires-Dist: tensorpack ==0.11 ; extra == 'tf'
118
- Requires-Dist: protobuf ==3.20.1 ; extra == 'tf'
119
- Requires-Dist: tensorflow-addons >=0.17.1 ; extra == 'tf'
120
- Requires-Dist: tf2onnx >=1.9.2 ; extra == 'tf'
121
- Requires-Dist: python-doctr ==0.8.1 ; extra == 'tf'
122
- Requires-Dist: pycocotools >=2.0.2 ; extra == 'tf'
123
- Requires-Dist: boto3 ==1.34.102 ; extra == 'tf'
124
- Requires-Dist: pdfplumber >=0.11.0 ; extra == 'tf'
125
- Requires-Dist: fasttext ==0.9.2 ; extra == 'tf'
126
- Requires-Dist: jdeskew >=0.2.2 ; extra == 'tf'
127
- Requires-Dist: apted ==1.0.3 ; extra == 'tf'
128
- Requires-Dist: distance ==0.1.3 ; extra == 'tf'
129
- Requires-Dist: lxml >=4.9.1 ; extra == 'tf'
128
+ Requires-Dist: pytest==8.0.2; extra == "test"
129
+ Requires-Dist: pytest-cov; extra == "test"
130
130
 
131
131
 
132
132
  <p align="center">
@@ -176,12 +176,16 @@ pipelines. Its core function does not depend on any specific deep learning libra
176
176
  [**Torchscript**](https://pytorch.org/docs/stable/jit.html) (CPU) as well and [**Detectron2**](https://github.com/facebookresearch/detectron2/tree/main/detectron2) is not required
177
177
  anymore for basic inference.
178
178
  - More angle predictors for determining the rotation of a document based on [**Tesseract**](https://github.com/tesseract-ocr/tesseract) and [**DocTr**](https://github.com/mindee/doctr)
179
- (not contained in the built-in Analyzer).
180
179
  - Token classification with [**LiLT**](https://github.com/jpWang/LiLT) via
181
180
  [**transformers**](https://github.com/huggingface/transformers).
182
181
  We have added a model wrapper for token classification with LiLT and added a some LiLT models to the model catalog
183
182
  that seem to look promising, especially if you want to train a model on non-english data. The training script for
184
- LayoutLM can be used for LiLT as well and we will be providing a notebook on how to train a model on a custom dataset soon.
183
+ LayoutLM can be used for LiLT as well.
184
+ - [**new**] There are two notebooks available that show, how to write a
185
+ [custom predictor](https://github.com/deepdoctection/notebooks/blob/main/Doclaynet_Analyzer_Config.ipynb) based on
186
+ a third party library that has not been supported yet and how to use
187
+ [advanced configuration](https://github.com/deepdoctection/notebooks/blob/main/Doclaynet_Analyzer_Config.ipynb) to
188
+ get links between layout segments e.g. captions and tables or figures.
185
189
 
186
190
  **deep**doctection provides on top of that methods for pre-processing inputs to models like cropping or resizing and to
187
191
  post-process results, like validating duplicate outputs, relating words to detected layout segments or ordering words
@@ -1,11 +1,11 @@
1
- deepdoctection/__init__.py,sha256=RZpawNRTJPKNPFuONawVOsYWdr-rI8PPNXZhlPtOKtc,12580
1
+ deepdoctection/__init__.py,sha256=fNUbaFAlK1JUXgPCmTu2UOLUMqW4HIgkaW4uOUYjYYg,12571
2
2
  deepdoctection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  deepdoctection/analyzer/__init__.py,sha256=icClxrd20XutD6LxLgEPIWceSs4j_QfI3szCE-9BL2w,729
4
- deepdoctection/analyzer/_config.py,sha256=0cWtaI2e3jHNhufHZAqMje0YTTDAogKAHVl4VpYojAo,4874
4
+ deepdoctection/analyzer/_config.py,sha256=NZl_REM8Ge2xfxvHN-mZR5KURcHfZii3xfMlKQwckbA,4864
5
5
  deepdoctection/analyzer/dd.py,sha256=DUOhOtwipHw5nabYqn3WGR9aZcgP0ma_bi_tjf9xscw,5973
6
- deepdoctection/analyzer/factory.py,sha256=T9jxtVLNFhocbsfWIGLPfFrEv21zQJzM6VdFt0yxMyg,23849
6
+ deepdoctection/analyzer/factory.py,sha256=xmo5F9X7I6lp0ZWJv8QavpMyG8UWYLvMi4qogsZV1_s,31507
7
7
  deepdoctection/configs/__init__.py,sha256=TX_P6tqDOF1LK1mi9ruAl7x0mtv1Asm8cYWCz3Pe2dk,646
8
- deepdoctection/configs/conf_dd_one.yaml,sha256=orP-oeqtWbz5S9FJZJKxy1UqMwOYjL9g0DOX-wbamqU,2239
8
+ deepdoctection/configs/conf_dd_one.yaml,sha256=td7XsyVhdXkhh5Pie7sT_WNjGTaxBOWgpxhkobHd1H0,2325
9
9
  deepdoctection/configs/conf_tesseract.yaml,sha256=oF6szDyoi15FHvq7yFUNIEjfA_jNLhGxoowiRsz_zY4,35
10
10
  deepdoctection/dataflow/__init__.py,sha256=CWRHMpmJaPk4xY_oIIFubCt-z11SguWrMWxHZ7rdrvY,845
11
11
  deepdoctection/dataflow/base.py,sha256=z4DCComSj5wStEPjtk0093cNNGfUMiDqx8dqz36nS_o,6221
@@ -20,7 +20,7 @@ deepdoctection/datapoint/annotation.py,sha256=FEgz4COxVDfjic0gG7kS6iHnWLBIgFnquQ
20
20
  deepdoctection/datapoint/box.py,sha256=tkFuVM6xfx2jL7W4UED4qHXV572LSRdIsVJbrEiyIxI,23524
21
21
  deepdoctection/datapoint/convert.py,sha256=Gw2IjNiEotPu1yuMZqrIYB0mCAwafKt-VgMnrHj6S7U,6808
22
22
  deepdoctection/datapoint/image.py,sha256=EvZlVwJjMAcL1z8RNPBvZ8fwdJvkGuGpcFxCP1y26Go,33045
23
- deepdoctection/datapoint/view.py,sha256=7qSX4DQw9OPQQSKfSjV8e5i6jLyu6hOMceSKJAob2N8,42154
23
+ deepdoctection/datapoint/view.py,sha256=1rVMuqucCrI5zlwyXMADJQBV38V_zSNFqFyBi3cMA1E,44914
24
24
  deepdoctection/datasets/__init__.py,sha256=-A3aR90aDsHPmVM35JavfnQ2itYSCn3ujl4krRni1QU,1076
25
25
  deepdoctection/datasets/adapter.py,sha256=Ly_vbOAgVI73V41FUccnSX1ECTOyesW_qsuvQuvOZbw,7796
26
26
  deepdoctection/datasets/base.py,sha256=DT4i-d74sIEiUNC6UspIHNJuHSK0t1dBv7qwadg4rLw,22341
@@ -44,7 +44,7 @@ deepdoctection/datasets/instances/xsl/pascal_voc.xsl,sha256=DlzFV2P8NtQKXVe96i-m
44
44
  deepdoctection/eval/__init__.py,sha256=rbns4tSEQ30QLj8h0mm3A0dCaKuN9LDxxpVypKKSXSE,932
45
45
  deepdoctection/eval/accmetric.py,sha256=4bND-xz9AZu9ACYRkEzn9V6Jn8MEiqnF7kxSp4k_baE,19655
46
46
  deepdoctection/eval/base.py,sha256=gCvhTdwEaCKplYTWPMjGvtB_0Vbq2KBJWFHq8mMlLPA,4814
47
- deepdoctection/eval/cocometric.py,sha256=Co7XaLQzp7qxw8UQaG2D68PzY6eA9aRNueeo_zaMJLM,8777
47
+ deepdoctection/eval/cocometric.py,sha256=4cpNmF3xZjInCOWOoVU_7itQxLI-zr0O6suNjPU2xWc,11020
48
48
  deepdoctection/eval/eval.py,sha256=B9PUZBjj6KzXHLOxUVn3QHiOcBQogfJmp9mjopbMo9k,19721
49
49
  deepdoctection/eval/registry.py,sha256=v4mp-s67vBVRu1nQzuGlYPViQnMSeIXEcF_WmvfUCoU,1051
50
50
  deepdoctection/eval/tedsmetric.py,sha256=rKw-734Y9CpBtIfkBSPQF2vAZxnIdWrI9Zc723P7RxI,9529
@@ -94,7 +94,7 @@ deepdoctection/mapper/d2struct.py,sha256=Dx-YnycsIQH4a5-9Gn_yMhiQ-gOFgMueNeH3rhX
94
94
  deepdoctection/mapper/hfstruct.py,sha256=2PjGKsYturVJBimLT1CahYh09KSRAFEHz_QNtC162kQ,5551
95
95
  deepdoctection/mapper/laylmstruct.py,sha256=abMZkYU2W0e_VcCm_c0ZXNFuv-lfMFWcTedcZS5EYvE,42935
96
96
  deepdoctection/mapper/maputils.py,sha256=eI6ZcDg9W5uB6xQNBZpMIdEd86HlCxTtkJuyROdTqiw,8146
97
- deepdoctection/mapper/match.py,sha256=E7Qna6zLDIxlI7puOL9BjjZKuRry-zONs8TLWmyEMIQ,9580
97
+ deepdoctection/mapper/match.py,sha256=pCWZpz2R8JahiKXCw7dxKRTLiPgJXeVDgkddDPLy_c0,9643
98
98
  deepdoctection/mapper/misc.py,sha256=rCqHOcsCfVPXs36AWK0rZ2kk0CUM3yXV370_zyIGBJ4,6518
99
99
  deepdoctection/mapper/pascalstruct.py,sha256=TzVU1p0oiw0nOuxTFFbEB9vXJxH1v6VUvTJ7MD0manU,3828
100
100
  deepdoctection/mapper/prodigystruct.py,sha256=Re4Sd_zAp6qOvbXZLmMJeG0IGEfMQxebuyDeZgMcTa8,6827
@@ -139,10 +139,10 @@ deepdoctection/utils/settings.py,sha256=k6OyuWbj-IPeaO9zT9RZ-5Yad1wNhWGYqGLZdtgX
139
139
  deepdoctection/utils/tqdm.py,sha256=cBUtR0L1x0KMeYrLP2rrzyzCamCjpQAKroHXLv81_pk,1820
140
140
  deepdoctection/utils/transform.py,sha256=3kCgsEeRkG1efCdkfvj7tUFMs-e2jbjbflq826F2GPU,8502
141
141
  deepdoctection/utils/types.py,sha256=_3dmPdCIZNLbgU5QP5k_c5phDf18xLe1kYL6t2nM45s,2953
142
- deepdoctection/utils/utils.py,sha256=ANzyIX6AY1yc-4gcn6yxksV84sPrJDaUurUNVatAFu8,5168
143
- deepdoctection/utils/viz.py,sha256=Xm6pKlhM29UWBBGZHlWFl9XYFDAqaYDdwHXwe26Hvqo,25728
144
- deepdoctection-0.35.dist-info/LICENSE,sha256=GQ0rUvuGdrMNEI3iHK5UQx6dIMU1QwAuyXsxUHn5MEQ,11351
145
- deepdoctection-0.35.dist-info/METADATA,sha256=B6pPQjRYWcqd1p-3ul3PhflYOcKq2ZpP5D-i8kr7qgk,19403
146
- deepdoctection-0.35.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
147
- deepdoctection-0.35.dist-info/top_level.txt,sha256=hs2DdoOL9h4mnHhmO82BT4pz4QATIoOZ20PZmlnxFI8,15
148
- deepdoctection-0.35.dist-info/RECORD,,
142
+ deepdoctection/utils/utils.py,sha256=csVs_VvCq4QBETPoE2JdTTL4MFYnD4xh-Js5vRb612g,6492
143
+ deepdoctection/utils/viz.py,sha256=Mok1d0V7NwlhAvO1S1Iq5YitKpVmOfH_XHTSlRelCB0,25902
144
+ deepdoctection-0.36.dist-info/LICENSE,sha256=GQ0rUvuGdrMNEI3iHK5UQx6dIMU1QwAuyXsxUHn5MEQ,11351
145
+ deepdoctection-0.36.dist-info/METADATA,sha256=E-zXgx0bTdSqbd88D_abscR_poEJaKJGIwlv2RFbQs8,19543
146
+ deepdoctection-0.36.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
147
+ deepdoctection-0.36.dist-info/top_level.txt,sha256=hs2DdoOL9h4mnHhmO82BT4pz4QATIoOZ20PZmlnxFI8,15
148
+ deepdoctection-0.36.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5