deepdoctection 0.44.1__py3-none-any.whl → 0.46__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.
- deepdoctection/__init__.py +7 -3
- deepdoctection/analyzer/config.py +44 -0
- deepdoctection/analyzer/factory.py +264 -7
- deepdoctection/configs/profiles.jsonl +2 -1
- deepdoctection/dataflow/parallel_map.py +7 -1
- deepdoctection/datapoint/box.py +5 -5
- deepdoctection/datapoint/image.py +5 -5
- deepdoctection/datapoint/view.py +73 -52
- deepdoctection/eval/cocometric.py +1 -0
- deepdoctection/extern/__init__.py +1 -0
- deepdoctection/extern/base.py +8 -1
- deepdoctection/extern/d2detect.py +1 -1
- deepdoctection/extern/doctrocr.py +18 -2
- deepdoctection/extern/fastlang.py +2 -2
- deepdoctection/extern/hflayoutlm.py +17 -10
- deepdoctection/extern/hflm.py +432 -7
- deepdoctection/extern/tessocr.py +17 -1
- deepdoctection/pipe/language.py +4 -4
- deepdoctection/pipe/lm.py +7 -3
- deepdoctection/pipe/order.py +12 -6
- deepdoctection/pipe/refine.py +10 -1
- deepdoctection/pipe/text.py +6 -0
- deepdoctection/pipe/transform.py +3 -0
- deepdoctection/utils/file_utils.py +34 -5
- deepdoctection/utils/logger.py +38 -1
- deepdoctection/utils/settings.py +2 -0
- deepdoctection/utils/transform.py +43 -18
- deepdoctection/utils/viz.py +24 -15
- {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/METADATA +16 -21
- {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/RECORD +33 -33
- {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/WHEEL +0 -0
- {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/licenses/LICENSE +0 -0
- {deepdoctection-0.44.1.dist-info → deepdoctection-0.46.dist-info}/top_level.txt +0 -0
deepdoctection/pipe/refine.py
CHANGED
|
@@ -27,7 +27,7 @@ from dataclasses import asdict
|
|
|
27
27
|
from itertools import chain, product
|
|
28
28
|
from typing import DefaultDict, Optional, Sequence, Union
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
from lazy_imports import try_import
|
|
31
31
|
|
|
32
32
|
from ..datapoint.annotation import ImageAnnotation
|
|
33
33
|
from ..datapoint.box import merge_boxes
|
|
@@ -35,10 +35,15 @@ from ..datapoint.image import Image, MetaAnnotation
|
|
|
35
35
|
from ..extern.base import DetectionResult
|
|
36
36
|
from ..mapper.maputils import MappingContextManager
|
|
37
37
|
from ..utils.error import ImageError
|
|
38
|
+
from ..utils.file_utils import networkx_available
|
|
38
39
|
from ..utils.settings import CellType, LayoutType, ObjectTypes, Relationships, TableType, get_type
|
|
39
40
|
from .base import PipelineComponent
|
|
40
41
|
from .registry import pipeline_component_registry
|
|
41
42
|
|
|
43
|
+
with try_import() as import_guard:
|
|
44
|
+
import networkx as nx # type: ignore
|
|
45
|
+
|
|
46
|
+
|
|
42
47
|
__all__ = ["TableSegmentationRefinementService", "generate_html_string"]
|
|
43
48
|
|
|
44
49
|
|
|
@@ -441,6 +446,10 @@ class TableSegmentationRefinementService(PipelineComponent):
|
|
|
441
446
|
table_names: Sequence of table object types.
|
|
442
447
|
cell_names: Sequence of cell object types.
|
|
443
448
|
"""
|
|
449
|
+
if not networkx_available():
|
|
450
|
+
raise ModuleNotFoundError(
|
|
451
|
+
"TableSegmentationRefinementService requires networkx. Please install separately."
|
|
452
|
+
)
|
|
444
453
|
self.table_name = table_names
|
|
445
454
|
self.cell_names = cell_names
|
|
446
455
|
super().__init__("table_segment_refine")
|
deepdoctection/pipe/text.py
CHANGED
|
@@ -129,6 +129,12 @@ class TextExtractionService(PipelineComponent):
|
|
|
129
129
|
width, height = self.predictor.get_width_height(predictor_input) # type: ignore
|
|
130
130
|
|
|
131
131
|
for detect_result in detect_result_list:
|
|
132
|
+
if width is not None and height is not None:
|
|
133
|
+
box = detect_result.box
|
|
134
|
+
if box:
|
|
135
|
+
if box[0] >= width or box[1] >= height or box[2] >= width or box[3] >= height:
|
|
136
|
+
continue
|
|
137
|
+
|
|
132
138
|
if isinstance(self.predictor, TextRecognizer):
|
|
133
139
|
detect_ann_id = detect_result.uuid
|
|
134
140
|
else:
|
deepdoctection/pipe/transform.py
CHANGED
|
@@ -77,6 +77,9 @@ class SimpleTransformService(PipelineComponent):
|
|
|
77
77
|
score=ann.score,
|
|
78
78
|
class_id=ann.category_id,
|
|
79
79
|
uuid=ann.annotation_id,
|
|
80
|
+
angle=detection_result.angle,
|
|
81
|
+
image_width=dp.width, # we need the original width, not the transformed width
|
|
82
|
+
image_height=dp.height, # same with height
|
|
80
83
|
)
|
|
81
84
|
)
|
|
82
85
|
output_detect_results = self.transform_predictor.transform_coords(detect_results)
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
Utilities for maintaining dependencies and dealing with external library packages. Parts of this file is adapted from
|
|
9
9
|
<https://github.com/huggingface/transformers/blob/master/src/transformers/file_utils.py>
|
|
10
10
|
"""
|
|
11
|
+
import importlib.metadata
|
|
11
12
|
import importlib.util
|
|
12
13
|
import multiprocessing as mp
|
|
13
14
|
import string
|
|
@@ -17,7 +18,6 @@ from shutil import which
|
|
|
17
18
|
from types import ModuleType
|
|
18
19
|
from typing import Any, Union, no_type_check
|
|
19
20
|
|
|
20
|
-
import importlib_metadata
|
|
21
21
|
import numpy as np
|
|
22
22
|
from packaging import version
|
|
23
23
|
|
|
@@ -72,9 +72,9 @@ def get_tf_version() -> str:
|
|
|
72
72
|
|
|
73
73
|
for pkg in candidates:
|
|
74
74
|
try:
|
|
75
|
-
tf_version =
|
|
75
|
+
tf_version = importlib.metadata.version(pkg)
|
|
76
76
|
break
|
|
77
|
-
except
|
|
77
|
+
except importlib.metadata.PackageNotFoundError:
|
|
78
78
|
pass
|
|
79
79
|
return tf_version
|
|
80
80
|
|
|
@@ -175,6 +175,19 @@ def get_pytorch_requirement() -> Requirement:
|
|
|
175
175
|
return "torch", pytorch_available(), _PYTORCH_ERR_MSG
|
|
176
176
|
|
|
177
177
|
|
|
178
|
+
_PYZMQ_AVAILABLE = importlib.util.find_spec("zmq") is not None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def pyzmq_available() -> bool:
|
|
182
|
+
"""
|
|
183
|
+
Returns whether pyzmq is installed.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
bool: True if pyzmq is installed, False otherwise.
|
|
187
|
+
"""
|
|
188
|
+
return bool(_PYZMQ_AVAILABLE)
|
|
189
|
+
|
|
190
|
+
|
|
178
191
|
# lxml
|
|
179
192
|
_LXML_AVAILABLE = importlib.util.find_spec("lxml") is not None
|
|
180
193
|
_LXML_ERR_MSG = f"lxml must be installed. {_GENERIC_ERR_MSG}"
|
|
@@ -232,7 +245,7 @@ _DISTANCE_ERR_MSG = f"distance must be installed. {_GENERIC_ERR_MSG}"
|
|
|
232
245
|
|
|
233
246
|
def distance_available() -> bool:
|
|
234
247
|
"""
|
|
235
|
-
Returns
|
|
248
|
+
Returns True if `distance` is available.
|
|
236
249
|
|
|
237
250
|
Returns:
|
|
238
251
|
bool: `True` if `distance` is available, False otherwise.
|
|
@@ -250,6 +263,22 @@ def get_distance_requirement() -> Requirement:
|
|
|
250
263
|
return "distance", distance_available(), _DISTANCE_ERR_MSG
|
|
251
264
|
|
|
252
265
|
|
|
266
|
+
# networkx
|
|
267
|
+
_NETWORKX_AVAILABLE = importlib.util.find_spec("networkx") is not None
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def networkx_available() -> bool:
|
|
271
|
+
"""
|
|
272
|
+
Checks if networkx is installed.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
bool: True if networkx is installed, False otherwise.
|
|
276
|
+
:return:
|
|
277
|
+
"""
|
|
278
|
+
return bool(_NETWORKX_AVAILABLE)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# numpy
|
|
253
282
|
_NUMPY_V1_ERR_MSG = "numpy v1 must be installed."
|
|
254
283
|
|
|
255
284
|
|
|
@@ -263,7 +292,7 @@ def numpy_v1_available() -> bool:
|
|
|
263
292
|
Returns:
|
|
264
293
|
True if the installed NumPy version is 1, otherwise False
|
|
265
294
|
"""
|
|
266
|
-
major_version = np.__version__.split(
|
|
295
|
+
major_version = np.__version__.split(".", maxsplit=1)[0]
|
|
267
296
|
print(f"major version: {major_version}")
|
|
268
297
|
if major_version in (1, "1"):
|
|
269
298
|
return True
|
deepdoctection/utils/logger.py
CHANGED
|
@@ -143,6 +143,43 @@ class FileFormatter(logging.Formatter):
|
|
|
143
143
|
|
|
144
144
|
|
|
145
145
|
_LOG_DIR = None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _coerce_log_level(val: Any) -> Union[int, str]:
|
|
149
|
+
"""Normalize environment log level values.
|
|
150
|
+
|
|
151
|
+
Accepts integer values (e.g., ``20``), numeric strings (``"20"``),
|
|
152
|
+
or names case-insensitively (``"info"``, ``"Warn"``, ...). Returns
|
|
153
|
+
either an integer level number or a valid uppercase level name
|
|
154
|
+
accepted by the :mod:`logging` module.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
val: The raw value from the environment variable ``LOG_LEVEL``.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
int | str: The corresponding logging level as an int or an
|
|
161
|
+
uppercase string. Defaults to ``"INFO"`` if the input is invalid.
|
|
162
|
+
"""
|
|
163
|
+
if isinstance(val, int):
|
|
164
|
+
return val
|
|
165
|
+
if val is None:
|
|
166
|
+
return "INFO"
|
|
167
|
+
s = str(val).strip()
|
|
168
|
+
if s.isdigit():
|
|
169
|
+
return int(s)
|
|
170
|
+
name = s.upper()
|
|
171
|
+
if name == "WARN":
|
|
172
|
+
name = "WARNING"
|
|
173
|
+
if name in logging._nameToLevel: # pylint: disable=W0212
|
|
174
|
+
return name
|
|
175
|
+
lvl = logging.getLevelName(name)
|
|
176
|
+
return lvl if isinstance(lvl, int) else "INFO"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# resolve level from LOG_LEVEL only
|
|
180
|
+
_ENV_LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
|
|
181
|
+
_RESOLVED_LOG_LEVEL = _coerce_log_level(_ENV_LOG_LEVEL)
|
|
182
|
+
|
|
146
183
|
_CONFIG_DICT: dict[str, Any] = {
|
|
147
184
|
"version": 1,
|
|
148
185
|
"disable_existing_loggers": False,
|
|
@@ -155,7 +192,7 @@ _CONFIG_DICT: dict[str, Any] = {
|
|
|
155
192
|
},
|
|
156
193
|
"root": {
|
|
157
194
|
"handlers": ["streamhandler"],
|
|
158
|
-
"level":
|
|
195
|
+
"level": _RESOLVED_LOG_LEVEL,
|
|
159
196
|
"propagate": os.environ.get("LOG_PROPAGATE", "False") in ENV_VARS_TRUE,
|
|
160
197
|
},
|
|
161
198
|
}
|
deepdoctection/utils/settings.py
CHANGED
|
@@ -108,6 +108,7 @@ class DocumentType(ObjectTypes):
|
|
|
108
108
|
GOVERNMENT_TENDERS = "government_tenders"
|
|
109
109
|
MANUALS = "manuals"
|
|
110
110
|
PATENTS = "patents"
|
|
111
|
+
BANK_STATEMENT = "bank_statement"
|
|
111
112
|
|
|
112
113
|
|
|
113
114
|
@object_types_registry.register("LayoutType")
|
|
@@ -296,6 +297,7 @@ class Languages(ObjectTypes):
|
|
|
296
297
|
BOSNIAN = "bos"
|
|
297
298
|
NORWEGIAN_NOVOSIBIRSK = "nno"
|
|
298
299
|
URDU = "urd"
|
|
300
|
+
SWAHILI = "swa"
|
|
299
301
|
NOT_DEFINED = "nn"
|
|
300
302
|
|
|
301
303
|
|
|
@@ -408,8 +408,35 @@ class RotationTransform(BaseTransform):
|
|
|
408
408
|
angle: Angle to rotate the image. Must be one of 90, 180, 270, or 360 degrees.
|
|
409
409
|
"""
|
|
410
410
|
self.angle = angle
|
|
411
|
-
self.image_width: Optional[int] = None
|
|
412
|
-
self.image_height: Optional[int] = None
|
|
411
|
+
self.image_width: Optional[Union[int, float]] = None
|
|
412
|
+
self.image_height: Optional[Union[int, float]] = None
|
|
413
|
+
|
|
414
|
+
def set_angle(self, angle: Literal[90, 180, 270, 360]) -> None:
|
|
415
|
+
"""
|
|
416
|
+
Set angle
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
angle: One of 90, 180, 270, or 360 degrees.
|
|
420
|
+
"""
|
|
421
|
+
self.angle = angle
|
|
422
|
+
|
|
423
|
+
def set_image_width(self, image_width: Union[int, float]) -> None:
|
|
424
|
+
"""
|
|
425
|
+
Set image width
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
image_width: Either a positive integer or 1.
|
|
429
|
+
"""
|
|
430
|
+
self.image_width = image_width
|
|
431
|
+
|
|
432
|
+
def set_image_height(self, image_height: Union[int, float]) -> None:
|
|
433
|
+
"""
|
|
434
|
+
Set image height
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
image_height: Either a positive integer or 1.
|
|
438
|
+
"""
|
|
439
|
+
self.image_height = image_height
|
|
413
440
|
|
|
414
441
|
def apply_image(self, img: PixelValues) -> PixelValues:
|
|
415
442
|
"""
|
|
@@ -442,17 +469,16 @@ class RotationTransform(BaseTransform):
|
|
|
442
469
|
raise ValueError("Initialize image_width and image_height first")
|
|
443
470
|
|
|
444
471
|
if self.angle == 90:
|
|
445
|
-
|
|
472
|
+
self.image_width = self.image_height
|
|
473
|
+
coords[:, [0, 1, 2, 3]] = coords[:, [1, 2, 3, 0]]
|
|
446
474
|
coords[:, [1, 3]] = self.image_width - coords[:, [1, 3]]
|
|
447
|
-
coords[:, [0, 1, 2, 3]] = coords[:, [0, 3, 2, 1]]
|
|
448
475
|
elif self.angle == 180:
|
|
449
|
-
coords[:, [0, 2]] = self.image_width - coords[:, [
|
|
450
|
-
coords[:, [1, 3]] = self.image_height - coords[:, [
|
|
451
|
-
coords[:, [0, 1, 2, 3]] = coords[:, [2, 3, 0, 1]]
|
|
476
|
+
coords[:, [0, 2]] = self.image_width - coords[:, [2, 0]]
|
|
477
|
+
coords[:, [1, 3]] = self.image_height - coords[:, [3, 1]]
|
|
452
478
|
elif self.angle == 270:
|
|
453
|
-
|
|
479
|
+
self.image_height = self.image_width
|
|
480
|
+
coords[:, [0, 1, 2, 3]] = coords[:, [3, 0, 1, 2]]
|
|
454
481
|
coords[:, [0, 2]] = self.image_height - coords[:, [0, 2]]
|
|
455
|
-
coords[:, [0, 1, 2, 3]] = coords[:, [2, 1, 0, 3]]
|
|
456
482
|
|
|
457
483
|
return coords
|
|
458
484
|
|
|
@@ -473,17 +499,16 @@ class RotationTransform(BaseTransform):
|
|
|
473
499
|
raise ValueError("Initialize image_width and image_height first")
|
|
474
500
|
|
|
475
501
|
if self.angle == 90:
|
|
476
|
-
|
|
477
|
-
coords[:, [0, 2]] =
|
|
478
|
-
coords[:, [0,
|
|
502
|
+
self.image_height = self.image_width
|
|
503
|
+
coords[:, [0, 1, 2, 3]] = coords[:, [3, 0, 1, 2]]
|
|
504
|
+
coords[:, [0, 2]] = self.image_height - coords[:, [0, 2]]
|
|
479
505
|
elif self.angle == 180:
|
|
480
|
-
coords[:, [0, 2]] = self.image_width - coords[:, [
|
|
481
|
-
coords[:, [1, 3]] = self.image_height - coords[:, [
|
|
482
|
-
coords[:, [0, 1, 2, 3]] = coords[:, [2, 3, 0, 1]]
|
|
506
|
+
coords[:, [0, 2]] = self.image_width - coords[:, [2, 0]]
|
|
507
|
+
coords[:, [1, 3]] = self.image_height - coords[:, [3, 1]]
|
|
483
508
|
elif self.angle == 270:
|
|
484
|
-
|
|
485
|
-
coords[:, [1, 3]] =
|
|
486
|
-
coords[:, [
|
|
509
|
+
self.image_width = self.image_height
|
|
510
|
+
coords[:, [0, 1, 2, 3]] = coords[:, [1, 2, 3, 0]]
|
|
511
|
+
coords[:, [1, 3]] = self.image_width - coords[:, [1, 3]]
|
|
487
512
|
return coords
|
|
488
513
|
|
|
489
514
|
def clone(self) -> RotationTransform:
|
deepdoctection/utils/viz.py
CHANGED
|
@@ -20,10 +20,11 @@ Visualisation utils. Copied and pasted from
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
import base64
|
|
23
|
+
import hashlib
|
|
23
24
|
import os
|
|
24
25
|
import sys
|
|
25
26
|
from io import BytesIO
|
|
26
|
-
from typing import Any, Optional, Sequence, no_type_check
|
|
27
|
+
from typing import Any, Optional, Sequence, Tuple, Union, no_type_check
|
|
27
28
|
|
|
28
29
|
import numpy as np
|
|
29
30
|
import numpy.typing as npt
|
|
@@ -177,17 +178,23 @@ _COLORS = (
|
|
|
177
178
|
)
|
|
178
179
|
|
|
179
180
|
|
|
180
|
-
def random_color(
|
|
181
|
+
def random_color(
|
|
182
|
+
rgb: bool = True, maximum: int = 255, deterministic_input_str: Optional[str] = None
|
|
183
|
+
) -> tuple[int, int, int]:
|
|
181
184
|
"""
|
|
182
185
|
Args:
|
|
183
186
|
rgb: Whether to return RGB colors or BGR colors.
|
|
184
187
|
maximum: Either 255 or 1.
|
|
188
|
+
deterministic_input_str: A string to use for deterministic color generation.
|
|
185
189
|
|
|
186
190
|
Returns:
|
|
187
191
|
A tuple of three integers representing the color.
|
|
188
192
|
"""
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
if deterministic_input_str:
|
|
194
|
+
hash_digest = hashlib.md5(deterministic_input_str.encode("utf-8")).hexdigest()
|
|
195
|
+
idx = int(hash_digest, 16) % len(_COLORS)
|
|
196
|
+
else:
|
|
197
|
+
idx = np.random.randint(0, len(_COLORS))
|
|
191
198
|
ret = _COLORS[idx] * maximum
|
|
192
199
|
if not rgb:
|
|
193
200
|
ret = ret[::-1]
|
|
@@ -197,7 +204,7 @@ def random_color(rgb: bool = True, maximum: int = 255) -> tuple[int, int, int]:
|
|
|
197
204
|
def draw_boxes(
|
|
198
205
|
np_image: PixelValues,
|
|
199
206
|
boxes: npt.NDArray[float32],
|
|
200
|
-
category_names_list: Optional[list[
|
|
207
|
+
category_names_list: Optional[list[Tuple[Union[str, None], Union[str, None]]]] = None,
|
|
201
208
|
color: Optional[BGR] = None,
|
|
202
209
|
font_scale: float = 1.0,
|
|
203
210
|
rectangle_thickness: int = 4,
|
|
@@ -210,7 +217,8 @@ def draw_boxes(
|
|
|
210
217
|
Args:
|
|
211
218
|
np_image: Image as `np.ndarray`.
|
|
212
219
|
boxes: A numpy array of shape Nx4 where each row is `[x1, y1, x2, y2]`.
|
|
213
|
-
category_names_list: List of N category
|
|
220
|
+
category_names_list: List of N tuples. The first element is the category name, whereas the second element is
|
|
221
|
+
the value, that is going to be displayed in the text box..
|
|
214
222
|
color: A 3-tuple BGR color (in range `[0, 255]`).
|
|
215
223
|
font_scale: Font scale of text box.
|
|
216
224
|
rectangle_thickness: Thickness of bounding box.
|
|
@@ -230,13 +238,14 @@ def draw_boxes(
|
|
|
230
238
|
category_to_color = {}
|
|
231
239
|
if box_color_by_category and category_names_list is not None:
|
|
232
240
|
category_names = set(category_names_list)
|
|
233
|
-
category_to_color = {
|
|
234
|
-
|
|
241
|
+
category_to_color = {
|
|
242
|
+
category[1]: random_color(deterministic_input_str=category[1]) for category in category_names
|
|
243
|
+
}
|
|
235
244
|
boxes = np.array(boxes, dtype="int32")
|
|
236
245
|
if category_names_list is not None:
|
|
237
246
|
assert len(category_names_list) == len(boxes), f"{len(category_names_list)} != {len(boxes)}"
|
|
238
247
|
else:
|
|
239
|
-
category_names_list = [None] * len(boxes)
|
|
248
|
+
category_names_list = [(None, None)] * len(boxes)
|
|
240
249
|
areas = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1)
|
|
241
250
|
sorted_inds = np.argsort(-areas) # draw large ones first
|
|
242
251
|
assert areas.min() > 0, areas.min()
|
|
@@ -255,12 +264,12 @@ def draw_boxes(
|
|
|
255
264
|
np_image = cv2.cvtColor(np_image, cv2.COLOR_GRAY2BGR).astype(np.uint8)
|
|
256
265
|
for i in sorted_inds:
|
|
257
266
|
box = boxes[i, :]
|
|
258
|
-
choose_color = category_to_color.get(category_names_list[i]) if category_to_color is not None else color
|
|
267
|
+
choose_color = category_to_color.get(category_names_list[i][1]) if category_to_color is not None else color
|
|
259
268
|
if choose_color is None:
|
|
260
269
|
choose_color = random_color()
|
|
261
|
-
if category_names_list[i] is not None:
|
|
270
|
+
if category_names_list[i][0] is not None:
|
|
262
271
|
np_image = viz_handler.draw_text(
|
|
263
|
-
np_image, (box[0], box[1]), category_names_list[i], color=choose_color, font_scale=font_scale
|
|
272
|
+
np_image, (box[0], box[1]), category_names_list[i][0], color=choose_color, font_scale=font_scale
|
|
264
273
|
)
|
|
265
274
|
np_image = viz_handler.draw_rectangle(
|
|
266
275
|
np_image, (box[0], box[1], box[2], box[3]), choose_color, rectangle_thickness
|
|
@@ -423,7 +432,7 @@ class VizPackageHandler:
|
|
|
423
432
|
|
|
424
433
|
@staticmethod
|
|
425
434
|
def _cv2_read_image(path: PathLikeOrStr) -> PixelValues:
|
|
426
|
-
return cv2.imread(os.fspath(path), cv2.IMREAD_COLOR).astype(np.uint8)
|
|
435
|
+
return cv2.imread(os.fspath(path), cv2.IMREAD_COLOR).astype(np.uint8) # type: ignore
|
|
427
436
|
|
|
428
437
|
@staticmethod
|
|
429
438
|
def _pillow_read_image(path: PathLikeOrStr) -> PixelValues:
|
|
@@ -517,7 +526,7 @@ class VizPackageHandler:
|
|
|
517
526
|
@staticmethod
|
|
518
527
|
def _cv2_convert_b64_to_np(image: B64Str) -> PixelValues:
|
|
519
528
|
np_array = np.fromstring(base64.b64decode(image), np.uint8) # type: ignore
|
|
520
|
-
np_array = cv2.imdecode(np_array, cv2.IMREAD_COLOR).astype(np.float32)
|
|
529
|
+
np_array = cv2.imdecode(np_array, cv2.IMREAD_COLOR).astype(np.float32) # type: ignore
|
|
521
530
|
return np_array.astype(uint8)
|
|
522
531
|
|
|
523
532
|
@staticmethod
|
|
@@ -543,7 +552,7 @@ class VizPackageHandler:
|
|
|
543
552
|
def _cv2_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
|
|
544
553
|
np_array = np.frombuffer(image_bytes, np.uint8)
|
|
545
554
|
np_image = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
|
|
546
|
-
return np_image
|
|
555
|
+
return np_image # type: ignore
|
|
547
556
|
|
|
548
557
|
@staticmethod
|
|
549
558
|
def _pillow_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepdoctection
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.46
|
|
4
4
|
Summary: Repository for Document AI
|
|
5
5
|
Home-page: https://github.com/deepdoctection/deepdoctection
|
|
6
6
|
Author: Dr. Janis Meyer
|
|
@@ -19,18 +19,15 @@ Description-Content-Type: text/markdown
|
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: catalogue==2.0.10
|
|
21
21
|
Requires-Dist: huggingface_hub>=0.26.0
|
|
22
|
-
Requires-Dist: importlib-metadata>=5.0.0
|
|
23
22
|
Requires-Dist: jsonlines==3.1.0
|
|
24
23
|
Requires-Dist: lazy-imports==0.3.1
|
|
25
24
|
Requires-Dist: mock==4.0.3
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist: numpy<2.0,>=1.21
|
|
25
|
+
Requires-Dist: numpy>2.0
|
|
28
26
|
Requires-Dist: packaging>=20.0
|
|
29
27
|
Requires-Dist: Pillow>=10.0.0
|
|
30
28
|
Requires-Dist: pypdf>=6.0.0
|
|
31
29
|
Requires-Dist: pypdfium2>=4.30.0
|
|
32
30
|
Requires-Dist: pyyaml>=6.0.1
|
|
33
|
-
Requires-Dist: pyzmq>=16
|
|
34
31
|
Requires-Dist: scipy>=1.13.1
|
|
35
32
|
Requires-Dist: termcolor>=1.1
|
|
36
33
|
Requires-Dist: tabulate>=0.7.7
|
|
@@ -38,18 +35,15 @@ Requires-Dist: tqdm>=4.64.0
|
|
|
38
35
|
Provides-Extra: tf
|
|
39
36
|
Requires-Dist: catalogue==2.0.10; extra == "tf"
|
|
40
37
|
Requires-Dist: huggingface_hub>=0.26.0; extra == "tf"
|
|
41
|
-
Requires-Dist: importlib-metadata>=5.0.0; extra == "tf"
|
|
42
38
|
Requires-Dist: jsonlines==3.1.0; extra == "tf"
|
|
43
39
|
Requires-Dist: lazy-imports==0.3.1; extra == "tf"
|
|
44
40
|
Requires-Dist: mock==4.0.3; extra == "tf"
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist: numpy<2.0,>=1.21; extra == "tf"
|
|
41
|
+
Requires-Dist: numpy>2.0; extra == "tf"
|
|
47
42
|
Requires-Dist: packaging>=20.0; extra == "tf"
|
|
48
43
|
Requires-Dist: Pillow>=10.0.0; extra == "tf"
|
|
49
44
|
Requires-Dist: pypdf>=6.0.0; extra == "tf"
|
|
50
45
|
Requires-Dist: pypdfium2>=4.30.0; extra == "tf"
|
|
51
46
|
Requires-Dist: pyyaml>=6.0.1; extra == "tf"
|
|
52
|
-
Requires-Dist: pyzmq>=16; extra == "tf"
|
|
53
47
|
Requires-Dist: scipy>=1.13.1; extra == "tf"
|
|
54
48
|
Requires-Dist: termcolor>=1.1; extra == "tf"
|
|
55
49
|
Requires-Dist: tabulate>=0.7.7; extra == "tf"
|
|
@@ -58,30 +52,28 @@ Requires-Dist: tensorpack==0.11; extra == "tf"
|
|
|
58
52
|
Requires-Dist: protobuf==3.20.1; extra == "tf"
|
|
59
53
|
Requires-Dist: tensorflow-addons>=0.17.1; extra == "tf"
|
|
60
54
|
Requires-Dist: tf2onnx>=1.9.2; extra == "tf"
|
|
61
|
-
Requires-Dist: python-doctr==0.
|
|
55
|
+
Requires-Dist: python-doctr==0.10.0; extra == "tf"
|
|
62
56
|
Requires-Dist: pycocotools>=2.0.2; extra == "tf"
|
|
63
57
|
Requires-Dist: boto3==1.34.102; extra == "tf"
|
|
64
58
|
Requires-Dist: pdfplumber>=0.11.0; extra == "tf"
|
|
65
|
-
Requires-Dist:
|
|
59
|
+
Requires-Dist: pyzmq>=16; extra == "tf"
|
|
66
60
|
Requires-Dist: jdeskew>=0.2.2; extra == "tf"
|
|
67
61
|
Requires-Dist: apted==1.0.3; extra == "tf"
|
|
68
62
|
Requires-Dist: distance==0.1.3; extra == "tf"
|
|
69
63
|
Requires-Dist: lxml>=4.9.1; extra == "tf"
|
|
64
|
+
Requires-Dist: networkx>=2.7.1; extra == "tf"
|
|
70
65
|
Provides-Extra: pt
|
|
71
66
|
Requires-Dist: catalogue==2.0.10; extra == "pt"
|
|
72
67
|
Requires-Dist: huggingface_hub>=0.26.0; extra == "pt"
|
|
73
|
-
Requires-Dist: importlib-metadata>=5.0.0; extra == "pt"
|
|
74
68
|
Requires-Dist: jsonlines==3.1.0; extra == "pt"
|
|
75
69
|
Requires-Dist: lazy-imports==0.3.1; extra == "pt"
|
|
76
70
|
Requires-Dist: mock==4.0.3; extra == "pt"
|
|
77
|
-
Requires-Dist:
|
|
78
|
-
Requires-Dist: numpy<2.0,>=1.21; extra == "pt"
|
|
71
|
+
Requires-Dist: numpy>2.0; extra == "pt"
|
|
79
72
|
Requires-Dist: packaging>=20.0; extra == "pt"
|
|
80
73
|
Requires-Dist: Pillow>=10.0.0; extra == "pt"
|
|
81
74
|
Requires-Dist: pypdf>=6.0.0; extra == "pt"
|
|
82
75
|
Requires-Dist: pypdfium2>=4.30.0; extra == "pt"
|
|
83
76
|
Requires-Dist: pyyaml>=6.0.1; extra == "pt"
|
|
84
|
-
Requires-Dist: pyzmq>=16; extra == "pt"
|
|
85
77
|
Requires-Dist: scipy>=1.13.1; extra == "pt"
|
|
86
78
|
Requires-Dist: termcolor>=1.1; extra == "pt"
|
|
87
79
|
Requires-Dist: tabulate>=0.7.7; extra == "pt"
|
|
@@ -89,15 +81,16 @@ Requires-Dist: tqdm>=4.64.0; extra == "pt"
|
|
|
89
81
|
Requires-Dist: timm>=0.9.16; extra == "pt"
|
|
90
82
|
Requires-Dist: transformers>=4.48.0; extra == "pt"
|
|
91
83
|
Requires-Dist: accelerate>=0.29.1; extra == "pt"
|
|
92
|
-
Requires-Dist: python-doctr==0.
|
|
84
|
+
Requires-Dist: python-doctr==0.10.0; extra == "pt"
|
|
93
85
|
Requires-Dist: pycocotools>=2.0.2; extra == "pt"
|
|
94
86
|
Requires-Dist: boto3==1.34.102; extra == "pt"
|
|
95
87
|
Requires-Dist: pdfplumber>=0.11.0; extra == "pt"
|
|
96
|
-
Requires-Dist:
|
|
88
|
+
Requires-Dist: pyzmq>=16; extra == "pt"
|
|
97
89
|
Requires-Dist: jdeskew>=0.2.2; extra == "pt"
|
|
98
90
|
Requires-Dist: apted==1.0.3; extra == "pt"
|
|
99
91
|
Requires-Dist: distance==0.1.3; extra == "pt"
|
|
100
92
|
Requires-Dist: lxml>=4.9.1; extra == "pt"
|
|
93
|
+
Requires-Dist: networkx>=2.7.1; extra == "pt"
|
|
101
94
|
Provides-Extra: docs
|
|
102
95
|
Requires-Dist: tensorpack==0.11; extra == "docs"
|
|
103
96
|
Requires-Dist: boto3==1.34.102; extra == "docs"
|
|
@@ -183,7 +176,8 @@ It also provides a framework for training, evaluating and inferencing Document A
|
|
|
183
176
|
[**LiLT**](https://github.com/jpWang/LiLT) and selected
|
|
184
177
|
[**Bert**](https://huggingface.co/docs/transformers/model_doc/xlm-roberta)-style including features like sliding windows.
|
|
185
178
|
- Text mining for native PDFs with [**pdfplumber**](https://github.com/jsvine/pdfplumber),
|
|
186
|
-
- Language detection with [**fastText**](https://github.com/facebookresearch/fastText)
|
|
179
|
+
- Language detection with `papluca/xlm-roberta-base-language-detection`. [**fastText**](https://github.com/facebookresearch/fastText) is still available but
|
|
180
|
+
but will be removed in a future version.
|
|
187
181
|
- Deskewing and rotating images with [**jdeskew**](https://github.com/phamquiluan/jdeskew).
|
|
188
182
|
- Fine-tuning and evaluation tools.
|
|
189
183
|
- Lot's of [tutorials](https://github.com/deepdoctection/notebooks)
|
|
@@ -294,7 +288,7 @@ alt="text" width="40%">
|
|
|
294
288
|
|
|
295
289
|
- Linux or macOS. Windows is not supported but there is a [Dockerfile](./docker/pytorch-cpu-jupyter/Dockerfile) available.
|
|
296
290
|
- Python >= 3.9
|
|
297
|
-
- 2.
|
|
291
|
+
- 2.6 \<= PyTorch **or** 2.11 \<= Tensorflow < 2.16. (For lower Tensorflow versions the code will only run on a GPU).
|
|
298
292
|
Tensorflow support will be stopped from Python 3.11 onwards.
|
|
299
293
|
- To fine-tune models, a GPU is recommended.
|
|
300
294
|
|
|
@@ -321,7 +315,7 @@ For a simple setup which is enough to parse documents with the default setting,
|
|
|
321
315
|
|
|
322
316
|
```
|
|
323
317
|
pip install transformers
|
|
324
|
-
pip install python-doctr==0.
|
|
318
|
+
pip install python-doctr==0.10.0 # If you use Python 3.10 or higher you can use the latest version.
|
|
325
319
|
pip install deepdoctection
|
|
326
320
|
```
|
|
327
321
|
|
|
@@ -329,8 +323,9 @@ pip install deepdoctection
|
|
|
329
323
|
|
|
330
324
|
```
|
|
331
325
|
pip install tensorpack
|
|
332
|
-
pip install python-doctr==0.9.0
|
|
333
326
|
pip install deepdoctection
|
|
327
|
+
pip install "numpy>=1.21,<2.0" --upgrade --force-reinstall # because TF 2.11 does not support numpy 2.0
|
|
328
|
+
pip install "python-doctr==0.9.0"
|
|
334
329
|
```
|
|
335
330
|
|
|
336
331
|
Both setups are sufficient to run the [**introduction notebook**](https://github.com/deepdoctection/notebooks/blob/main/Get_Started.ipynb).
|