python-doctr 1.0.0__py3-none-any.whl → 1.0.1__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.
- doctr/contrib/artefacts.py +1 -1
- doctr/contrib/base.py +1 -1
- doctr/datasets/coco_text.py +1 -1
- doctr/datasets/cord.py +1 -1
- doctr/datasets/datasets/base.py +1 -1
- doctr/datasets/datasets/pytorch.py +1 -1
- doctr/datasets/detection.py +1 -1
- doctr/datasets/doc_artefacts.py +1 -1
- doctr/datasets/funsd.py +1 -1
- doctr/datasets/generator/base.py +1 -1
- doctr/datasets/generator/pytorch.py +1 -1
- doctr/datasets/ic03.py +1 -1
- doctr/datasets/ic13.py +1 -1
- doctr/datasets/iiit5k.py +1 -1
- doctr/datasets/iiithws.py +1 -1
- doctr/datasets/imgur5k.py +1 -1
- doctr/datasets/mjsynth.py +1 -1
- doctr/datasets/ocr.py +1 -1
- doctr/datasets/orientation.py +1 -1
- doctr/datasets/recognition.py +1 -1
- doctr/datasets/sroie.py +1 -1
- doctr/datasets/svhn.py +1 -1
- doctr/datasets/svt.py +1 -1
- doctr/datasets/synthtext.py +1 -1
- doctr/datasets/utils.py +1 -1
- doctr/datasets/vocabs.py +1 -1
- doctr/datasets/wildreceipt.py +1 -1
- doctr/file_utils.py +1 -1
- doctr/io/elements.py +1 -1
- doctr/io/html.py +1 -1
- doctr/io/image/base.py +1 -1
- doctr/io/image/pytorch.py +1 -1
- doctr/io/pdf.py +1 -1
- doctr/io/reader.py +1 -1
- doctr/models/_utils.py +55 -17
- doctr/models/builder.py +1 -1
- doctr/models/classification/magc_resnet/pytorch.py +1 -1
- doctr/models/classification/mobilenet/pytorch.py +1 -1
- doctr/models/classification/predictor/pytorch.py +1 -1
- doctr/models/classification/resnet/pytorch.py +1 -1
- doctr/models/classification/textnet/pytorch.py +1 -1
- doctr/models/classification/vgg/pytorch.py +1 -1
- doctr/models/classification/vip/layers/pytorch.py +1 -1
- doctr/models/classification/vip/pytorch.py +1 -1
- doctr/models/classification/vit/pytorch.py +1 -1
- doctr/models/classification/zoo.py +1 -1
- doctr/models/core.py +1 -1
- doctr/models/detection/_utils/base.py +1 -1
- doctr/models/detection/_utils/pytorch.py +1 -1
- doctr/models/detection/core.py +1 -1
- doctr/models/detection/differentiable_binarization/base.py +1 -1
- doctr/models/detection/differentiable_binarization/pytorch.py +1 -1
- doctr/models/detection/fast/base.py +1 -1
- doctr/models/detection/fast/pytorch.py +1 -1
- doctr/models/detection/linknet/base.py +1 -1
- doctr/models/detection/linknet/pytorch.py +1 -1
- doctr/models/detection/predictor/pytorch.py +1 -1
- doctr/models/detection/zoo.py +1 -1
- doctr/models/factory/hub.py +18 -13
- doctr/models/kie_predictor/base.py +1 -1
- doctr/models/kie_predictor/pytorch.py +1 -1
- doctr/models/modules/layers/pytorch.py +1 -1
- doctr/models/modules/transformer/pytorch.py +1 -1
- doctr/models/modules/vision_transformer/pytorch.py +1 -1
- doctr/models/predictor/base.py +1 -1
- doctr/models/predictor/pytorch.py +1 -1
- doctr/models/preprocessor/pytorch.py +1 -1
- doctr/models/recognition/core.py +1 -1
- doctr/models/recognition/crnn/pytorch.py +1 -1
- doctr/models/recognition/master/base.py +1 -1
- doctr/models/recognition/master/pytorch.py +1 -1
- doctr/models/recognition/parseq/base.py +1 -1
- doctr/models/recognition/parseq/pytorch.py +1 -1
- doctr/models/recognition/predictor/_utils.py +1 -1
- doctr/models/recognition/predictor/pytorch.py +1 -1
- doctr/models/recognition/sar/pytorch.py +1 -1
- doctr/models/recognition/utils.py +1 -1
- doctr/models/recognition/viptr/pytorch.py +1 -1
- doctr/models/recognition/vitstr/base.py +1 -1
- doctr/models/recognition/vitstr/pytorch.py +1 -1
- doctr/models/recognition/zoo.py +1 -1
- doctr/models/utils/pytorch.py +2 -1
- doctr/models/zoo.py +1 -1
- doctr/transforms/functional/base.py +3 -2
- doctr/transforms/functional/pytorch.py +1 -1
- doctr/transforms/modules/base.py +2 -2
- doctr/transforms/modules/pytorch.py +1 -1
- doctr/utils/common_types.py +1 -1
- doctr/utils/data.py +1 -2
- doctr/utils/fonts.py +1 -1
- doctr/utils/geometry.py +1 -1
- doctr/utils/metrics.py +1 -1
- doctr/utils/multithreading.py +1 -1
- doctr/utils/reconstitution.py +1 -1
- doctr/utils/repr.py +1 -1
- doctr/utils/visualization.py +1 -1
- doctr/version.py +1 -1
- {python_doctr-1.0.0.dist-info → python_doctr-1.0.1.dist-info}/METADATA +13 -6
- python_doctr-1.0.1.dist-info/RECORD +149 -0
- {python_doctr-1.0.0.dist-info → python_doctr-1.0.1.dist-info}/WHEEL +1 -1
- python_doctr-1.0.0.dist-info/RECORD +0 -149
- {python_doctr-1.0.0.dist-info → python_doctr-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {python_doctr-1.0.0.dist-info → python_doctr-1.0.1.dist-info}/top_level.txt +0 -0
- {python_doctr-1.0.0.dist-info → python_doctr-1.0.1.dist-info}/zip-safe +0 -0
doctr/contrib/artefacts.py
CHANGED
doctr/contrib/base.py
CHANGED
doctr/datasets/coco_text.py
CHANGED
doctr/datasets/cord.py
CHANGED
doctr/datasets/datasets/base.py
CHANGED
doctr/datasets/detection.py
CHANGED
doctr/datasets/doc_artefacts.py
CHANGED
doctr/datasets/funsd.py
CHANGED
doctr/datasets/generator/base.py
CHANGED
doctr/datasets/ic03.py
CHANGED
doctr/datasets/ic13.py
CHANGED
doctr/datasets/iiit5k.py
CHANGED
doctr/datasets/iiithws.py
CHANGED
doctr/datasets/imgur5k.py
CHANGED
doctr/datasets/mjsynth.py
CHANGED
doctr/datasets/ocr.py
CHANGED
doctr/datasets/orientation.py
CHANGED
doctr/datasets/recognition.py
CHANGED
doctr/datasets/sroie.py
CHANGED
doctr/datasets/svhn.py
CHANGED
doctr/datasets/svt.py
CHANGED
doctr/datasets/synthtext.py
CHANGED
doctr/datasets/utils.py
CHANGED
doctr/datasets/vocabs.py
CHANGED
doctr/datasets/wildreceipt.py
CHANGED
doctr/file_utils.py
CHANGED
doctr/io/elements.py
CHANGED
doctr/io/html.py
CHANGED
doctr/io/image/base.py
CHANGED
doctr/io/image/pytorch.py
CHANGED
doctr/io/pdf.py
CHANGED
doctr/io/reader.py
CHANGED
doctr/models/_utils.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (C) 2021-
|
|
1
|
+
# Copyright (C) 2021-2026, Mindee.
|
|
2
2
|
|
|
3
3
|
# This program is licensed under the Apache License 2.0.
|
|
4
4
|
# See LICENSE or go to <https://opensource.org/licenses/Apache-2.0> for full license details.
|
|
@@ -26,6 +26,8 @@ def get_max_width_length_ratio(contour: np.ndarray) -> float:
|
|
|
26
26
|
the maximum shape ratio
|
|
27
27
|
"""
|
|
28
28
|
_, (w, h), _ = cv2.minAreaRect(contour)
|
|
29
|
+
if w == 0 or h == 0:
|
|
30
|
+
return 0.0
|
|
29
31
|
return max(w / h, h / w)
|
|
30
32
|
|
|
31
33
|
|
|
@@ -53,7 +55,7 @@ def estimate_orientation(
|
|
|
53
55
|
the estimated angle of the page (clockwise, negative for left side rotation, positive for right side rotation)
|
|
54
56
|
"""
|
|
55
57
|
assert len(img.shape) == 3 and img.shape[-1] in [1, 3], f"Image shape {img.shape} not supported"
|
|
56
|
-
|
|
58
|
+
|
|
57
59
|
# Convert image to grayscale if necessary
|
|
58
60
|
if img.shape[-1] == 3:
|
|
59
61
|
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
@@ -62,11 +64,14 @@ def estimate_orientation(
|
|
|
62
64
|
else:
|
|
63
65
|
thresh = img.astype(np.uint8)
|
|
64
66
|
|
|
65
|
-
page_orientation, orientation_confidence = general_page_orientation or (
|
|
66
|
-
|
|
67
|
+
page_orientation, orientation_confidence = general_page_orientation or (0, 0.0)
|
|
68
|
+
is_confident = page_orientation is not None and orientation_confidence >= min_confidence
|
|
69
|
+
base_angle = page_orientation if is_confident else 0
|
|
70
|
+
|
|
71
|
+
if is_confident:
|
|
67
72
|
# We rotate the image to the general orientation which improves the detection
|
|
68
73
|
# No expand needed bitmap is already padded
|
|
69
|
-
thresh = rotate_image(thresh, -
|
|
74
|
+
thresh = rotate_image(thresh, -base_angle)
|
|
70
75
|
else: # That's only required if we do not work on the detection models bin map
|
|
71
76
|
# try to merge words in lines
|
|
72
77
|
(h, w) = img.shape[:2]
|
|
@@ -88,30 +93,63 @@ def estimate_orientation(
|
|
|
88
93
|
angles = []
|
|
89
94
|
for contour in contours[:n_ct]:
|
|
90
95
|
_, (w, h), angle = cv2.minAreaRect(contour)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
|
|
97
|
+
# OpenCV version-proof normalization: force 'w' to be the long side
|
|
98
|
+
# so the angle is consistently relative to the major axis.
|
|
99
|
+
# https://github.com/opencv/opencv/pull/28051/changes
|
|
100
|
+
if w < h:
|
|
101
|
+
w, h = h, w
|
|
102
|
+
angle -= 90
|
|
103
|
+
|
|
104
|
+
# Normalize angle to be within [-90, 90]
|
|
105
|
+
while angle <= -90:
|
|
106
|
+
angle += 180
|
|
107
|
+
while angle > 90:
|
|
108
|
+
angle -= 180
|
|
109
|
+
|
|
110
|
+
if h > 0:
|
|
111
|
+
if w / h > ratio_threshold_for_lines: # select only contours with ratio like lines
|
|
112
|
+
angles.append(angle)
|
|
113
|
+
elif w / h < 1 / ratio_threshold_for_lines: # if lines are vertical, substract 90 degree
|
|
114
|
+
angles.append(angle - 90)
|
|
95
115
|
|
|
96
116
|
if len(angles) == 0:
|
|
97
|
-
|
|
117
|
+
skew_angle = 0 # in case no angles is found
|
|
98
118
|
else:
|
|
119
|
+
# median_low picks a value from the data to avoid outliers
|
|
99
120
|
median = -median_low(angles)
|
|
100
|
-
|
|
121
|
+
skew_angle = -round(median) if abs(median) != 0 else 0
|
|
122
|
+
|
|
123
|
+
# Resolve the 90-degree flip ambiguity.
|
|
124
|
+
# If the estimation is exactly 90/-90, it's usually a vertical detection of horizontal lines.
|
|
125
|
+
if abs(skew_angle) == 90:
|
|
126
|
+
skew_angle = 0
|
|
101
127
|
|
|
102
128
|
# combine with the general orientation and the estimated angle
|
|
103
|
-
|
|
129
|
+
# Apply the detected skew to our base orientation
|
|
130
|
+
final_angle = base_angle + skew_angle
|
|
131
|
+
|
|
132
|
+
# Standardize result to [-179, 180] range to handle wrap-around cases (e.g., 180 + -31)
|
|
133
|
+
while final_angle > 180:
|
|
134
|
+
final_angle -= 360
|
|
135
|
+
while final_angle <= -180:
|
|
136
|
+
final_angle += 360
|
|
137
|
+
|
|
138
|
+
if is_confident:
|
|
139
|
+
# If the estimated angle is perpendicular, treat it as 0 to avoid wrong flips
|
|
140
|
+
if abs(skew_angle) % 90 == 0:
|
|
141
|
+
return page_orientation
|
|
142
|
+
|
|
104
143
|
# special case where the estimated angle is mostly wrong:
|
|
105
144
|
# case 1: - and + swapped
|
|
106
145
|
# case 2: estimated angle is completely wrong
|
|
107
146
|
# so in this case we prefer the general page orientation
|
|
108
|
-
if abs(
|
|
147
|
+
if abs(skew_angle) == abs(page_orientation) and page_orientation != 0:
|
|
109
148
|
return page_orientation
|
|
110
|
-
estimated_angle = estimated_angle if page_orientation == 0 else page_orientation + estimated_angle
|
|
111
|
-
if estimated_angle > 180:
|
|
112
|
-
estimated_angle -= 360
|
|
113
149
|
|
|
114
|
-
return
|
|
150
|
+
return int(
|
|
151
|
+
final_angle
|
|
152
|
+
) # return the clockwise angle (negative - left side rotation, positive - right side rotation)
|
|
115
153
|
|
|
116
154
|
|
|
117
155
|
def rectify_crops(
|
doctr/models/builder.py
CHANGED
doctr/models/core.py
CHANGED
doctr/models/detection/core.py
CHANGED
doctr/models/detection/zoo.py
CHANGED
doctr/models/factory/hub.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (C) 2021-
|
|
1
|
+
# Copyright (C) 2021-2026, Mindee.
|
|
2
2
|
|
|
3
3
|
# This program is licensed under the Apache License 2.0.
|
|
4
4
|
# See LICENSE or go to <https://opensource.org/licenses/Apache-2.0> for full license details.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
|
-
import os
|
|
11
10
|
import subprocess
|
|
11
|
+
import tempfile
|
|
12
12
|
import textwrap
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any
|
|
@@ -16,9 +16,7 @@ from typing import Any
|
|
|
16
16
|
import torch
|
|
17
17
|
from huggingface_hub import (
|
|
18
18
|
HfApi,
|
|
19
|
-
Repository,
|
|
20
19
|
get_token,
|
|
21
|
-
get_token_permission,
|
|
22
20
|
hf_hub_download,
|
|
23
21
|
login,
|
|
24
22
|
)
|
|
@@ -38,9 +36,9 @@ AVAILABLE_ARCHS = {
|
|
|
38
36
|
def login_to_hub() -> None: # pragma: no cover
|
|
39
37
|
"""Login to huggingface hub"""
|
|
40
38
|
access_token = get_token()
|
|
41
|
-
if access_token is not None
|
|
39
|
+
if access_token is not None:
|
|
42
40
|
logging.info("Huggingface Hub token found and valid")
|
|
43
|
-
login(token=access_token
|
|
41
|
+
login(token=access_token)
|
|
44
42
|
else:
|
|
45
43
|
login()
|
|
46
44
|
# check if git lfs is installed
|
|
@@ -161,16 +159,23 @@ def push_to_hf_hub(model: Any, model_name: str, task: str, **kwargs) -> None: #
|
|
|
161
159
|
|
|
162
160
|
commit_message = f"Add {model_name} model"
|
|
163
161
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
# Create repository
|
|
163
|
+
api = HfApi()
|
|
164
|
+
api.create_repo(model_name, token=get_token(), exist_ok=False)
|
|
167
165
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
# Save model files to a temporary directory
|
|
167
|
+
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
168
|
+
_save_model_and_config_for_hf_hub(model, tmp_dir, arch=arch, task=task)
|
|
169
|
+
readme_path = Path(tmp_dir) / "README.md"
|
|
171
170
|
readme_path.write_text(readme)
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
# Upload all files to the hub
|
|
173
|
+
api.upload_folder(
|
|
174
|
+
folder_path=tmp_dir,
|
|
175
|
+
repo_id=model_name,
|
|
176
|
+
commit_message=commit_message,
|
|
177
|
+
token=get_token(),
|
|
178
|
+
)
|
|
174
179
|
|
|
175
180
|
|
|
176
181
|
def from_hub(repo_id: str, **kwargs: Any):
|