onnxtr 0.5.1__py3-none-any.whl → 0.6.0__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.
Files changed (56) hide show
  1. onnxtr/contrib/__init__.py +1 -0
  2. onnxtr/contrib/artefacts.py +6 -8
  3. onnxtr/contrib/base.py +7 -16
  4. onnxtr/file_utils.py +1 -3
  5. onnxtr/io/elements.py +45 -59
  6. onnxtr/io/html.py +0 -2
  7. onnxtr/io/image.py +1 -4
  8. onnxtr/io/pdf.py +3 -5
  9. onnxtr/io/reader.py +4 -10
  10. onnxtr/models/_utils.py +10 -17
  11. onnxtr/models/builder.py +17 -30
  12. onnxtr/models/classification/models/mobilenet.py +7 -12
  13. onnxtr/models/classification/predictor/base.py +6 -7
  14. onnxtr/models/classification/zoo.py +25 -11
  15. onnxtr/models/detection/_utils/base.py +3 -7
  16. onnxtr/models/detection/core.py +2 -8
  17. onnxtr/models/detection/models/differentiable_binarization.py +10 -17
  18. onnxtr/models/detection/models/fast.py +10 -17
  19. onnxtr/models/detection/models/linknet.py +10 -17
  20. onnxtr/models/detection/postprocessor/base.py +3 -9
  21. onnxtr/models/detection/predictor/base.py +4 -5
  22. onnxtr/models/detection/zoo.py +20 -6
  23. onnxtr/models/engine.py +9 -9
  24. onnxtr/models/factory/hub.py +3 -7
  25. onnxtr/models/predictor/base.py +29 -30
  26. onnxtr/models/predictor/predictor.py +4 -5
  27. onnxtr/models/preprocessor/base.py +8 -12
  28. onnxtr/models/recognition/core.py +0 -1
  29. onnxtr/models/recognition/models/crnn.py +11 -23
  30. onnxtr/models/recognition/models/master.py +9 -15
  31. onnxtr/models/recognition/models/parseq.py +8 -12
  32. onnxtr/models/recognition/models/sar.py +8 -12
  33. onnxtr/models/recognition/models/vitstr.py +9 -15
  34. onnxtr/models/recognition/predictor/_utils.py +6 -9
  35. onnxtr/models/recognition/predictor/base.py +3 -3
  36. onnxtr/models/recognition/utils.py +2 -7
  37. onnxtr/models/recognition/zoo.py +19 -7
  38. onnxtr/models/zoo.py +7 -9
  39. onnxtr/transforms/base.py +17 -6
  40. onnxtr/utils/common_types.py +7 -8
  41. onnxtr/utils/data.py +7 -11
  42. onnxtr/utils/fonts.py +1 -6
  43. onnxtr/utils/geometry.py +18 -49
  44. onnxtr/utils/multithreading.py +3 -5
  45. onnxtr/utils/reconstitution.py +6 -8
  46. onnxtr/utils/repr.py +1 -2
  47. onnxtr/utils/visualization.py +12 -21
  48. onnxtr/utils/vocabs.py +1 -2
  49. onnxtr/version.py +1 -1
  50. {onnxtr-0.5.1.dist-info → onnxtr-0.6.0.dist-info}/METADATA +70 -41
  51. onnxtr-0.6.0.dist-info/RECORD +75 -0
  52. {onnxtr-0.5.1.dist-info → onnxtr-0.6.0.dist-info}/WHEEL +1 -1
  53. onnxtr-0.5.1.dist-info/RECORD +0 -75
  54. {onnxtr-0.5.1.dist-info → onnxtr-0.6.0.dist-info}/LICENSE +0 -0
  55. {onnxtr-0.5.1.dist-info → onnxtr-0.6.0.dist-info}/top_level.txt +0 -0
  56. {onnxtr-0.5.1.dist-info → onnxtr-0.6.0.dist-info}/zip-safe +0 -0
onnxtr/utils/geometry.py CHANGED
@@ -5,7 +5,6 @@
5
5
 
6
6
  from copy import deepcopy
7
7
  from math import ceil
8
- from typing import List, Optional, Tuple, Union
9
8
 
10
9
  import cv2
11
10
  import numpy as np
@@ -34,11 +33,9 @@ def bbox_to_polygon(bbox: BoundingBox) -> Polygon4P:
34
33
  """Convert a bounding box to a polygon
35
34
 
36
35
  Args:
37
- ----
38
36
  bbox: a bounding box
39
37
 
40
38
  Returns:
41
- -------
42
39
  a polygon
43
40
  """
44
41
  return bbox[0], (bbox[1][0], bbox[0][1]), (bbox[0][0], bbox[1][1]), bbox[1]
@@ -48,29 +45,27 @@ def polygon_to_bbox(polygon: Polygon4P) -> BoundingBox:
48
45
  """Convert a polygon to a bounding box
49
46
 
50
47
  Args:
51
- ----
52
48
  polygon: a polygon
53
49
 
54
50
  Returns:
55
- -------
56
51
  a bounding box
57
52
  """
58
53
  x, y = zip(*polygon)
59
54
  return (min(x), min(y)), (max(x), max(y))
60
55
 
61
56
 
62
- def detach_scores(boxes: List[np.ndarray]) -> Tuple[List[np.ndarray], List[np.ndarray]]:
57
+ def detach_scores(boxes: list[np.ndarray]) -> tuple[list[np.ndarray], list[np.ndarray]]:
63
58
  """Detach the objectness scores from box predictions
59
+
64
60
  Args:
65
- ----
66
61
  boxes: list of arrays with boxes of shape (N, 5) or (N, 5, 2)
62
+
67
63
  Returns:
68
- -------
69
64
  a tuple of two lists: the first one contains the boxes without the objectness scores,
70
65
  the second one contains the objectness scores
71
66
  """
72
67
 
73
- def _detach(boxes: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
68
+ def _detach(boxes: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
74
69
  if boxes.ndim == 2:
75
70
  return boxes[:, :-1], boxes[:, -1]
76
71
  return boxes[:, :-1], boxes[:, -1, -1]
@@ -83,12 +78,10 @@ def shape_translate(data: np.ndarray, format: str) -> np.ndarray:
83
78
  """Translate the shape of the input data to the desired format
84
79
 
85
80
  Args:
86
- ----
87
81
  data: input data in shape (B, C, H, W) or (B, H, W, C) or (C, H, W) or (H, W, C)
88
82
  format: target format ('BCHW', 'BHWC', 'CHW', or 'HWC')
89
83
 
90
84
  Returns:
91
- -------
92
85
  the reshaped data
93
86
  """
94
87
  # Get the current shape
@@ -120,11 +113,10 @@ def shape_translate(data: np.ndarray, format: str) -> np.ndarray:
120
113
  return data
121
114
 
122
115
 
123
- def resolve_enclosing_bbox(bboxes: Union[List[BoundingBox], np.ndarray]) -> Union[BoundingBox, np.ndarray]:
116
+ def resolve_enclosing_bbox(bboxes: list[BoundingBox] | np.ndarray) -> BoundingBox | np.ndarray:
124
117
  """Compute enclosing bbox either from:
125
118
 
126
119
  Args:
127
- ----
128
120
  bboxes: boxes in one of the following formats:
129
121
 
130
122
  - an array of boxes: (*, 4), where boxes have this shape:
@@ -133,7 +125,6 @@ def resolve_enclosing_bbox(bboxes: Union[List[BoundingBox], np.ndarray]) -> Unio
133
125
  - a list of BoundingBox
134
126
 
135
127
  Returns:
136
- -------
137
128
  a (1, 4) array (enclosing boxarray), or a BoundingBox
138
129
  """
139
130
  if isinstance(bboxes, np.ndarray):
@@ -144,11 +135,10 @@ def resolve_enclosing_bbox(bboxes: Union[List[BoundingBox], np.ndarray]) -> Unio
144
135
  return (min(x), min(y)), (max(x), max(y))
145
136
 
146
137
 
147
- def resolve_enclosing_rbbox(rbboxes: List[np.ndarray], intermed_size: int = 1024) -> np.ndarray:
138
+ def resolve_enclosing_rbbox(rbboxes: list[np.ndarray], intermed_size: int = 1024) -> np.ndarray:
148
139
  """Compute enclosing rotated bbox either from:
149
140
 
150
141
  Args:
151
- ----
152
142
  rbboxes: boxes in one of the following formats:
153
143
 
154
144
  - an array of boxes: (*, 4, 2), where boxes have this shape:
@@ -158,26 +148,23 @@ def resolve_enclosing_rbbox(rbboxes: List[np.ndarray], intermed_size: int = 1024
158
148
  intermed_size: size of the intermediate image
159
149
 
160
150
  Returns:
161
- -------
162
151
  a (4, 2) array (enclosing rotated box)
163
152
  """
164
153
  cloud: np.ndarray = np.concatenate(rbboxes, axis=0)
165
154
  # Convert to absolute for minAreaRect
166
155
  cloud *= intermed_size
167
156
  rect = cv2.minAreaRect(cloud.astype(np.int32))
168
- return cv2.boxPoints(rect) / intermed_size # type: ignore[return-value]
157
+ return cv2.boxPoints(rect) / intermed_size
169
158
 
170
159
 
171
160
  def rotate_abs_points(points: np.ndarray, angle: float = 0.0) -> np.ndarray:
172
161
  """Rotate points counter-clockwise.
173
162
 
174
163
  Args:
175
- ----
176
164
  points: array of size (N, 2)
177
165
  angle: angle between -90 and +90 degrees
178
166
 
179
167
  Returns:
180
- -------
181
168
  Rotated points
182
169
  """
183
170
  angle_rad = angle * np.pi / 180.0 # compute radian angle for np functions
@@ -187,16 +174,14 @@ def rotate_abs_points(points: np.ndarray, angle: float = 0.0) -> np.ndarray:
187
174
  return np.matmul(points, rotation_mat.T)
188
175
 
189
176
 
190
- def compute_expanded_shape(img_shape: Tuple[int, int], angle: float) -> Tuple[int, int]:
177
+ def compute_expanded_shape(img_shape: tuple[int, int], angle: float) -> tuple[int, int]:
191
178
  """Compute the shape of an expanded rotated image
192
179
 
193
180
  Args:
194
- ----
195
181
  img_shape: the height and width of the image
196
182
  angle: angle between -90 and +90 degrees
197
183
 
198
184
  Returns:
199
- -------
200
185
  the height and width of the rotated image
201
186
  """
202
187
  points: np.ndarray = np.array([
@@ -213,21 +198,19 @@ def compute_expanded_shape(img_shape: Tuple[int, int], angle: float) -> Tuple[in
213
198
  def rotate_abs_geoms(
214
199
  geoms: np.ndarray,
215
200
  angle: float,
216
- img_shape: Tuple[int, int],
201
+ img_shape: tuple[int, int],
217
202
  expand: bool = True,
218
203
  ) -> np.ndarray:
219
204
  """Rotate a batch of bounding boxes or polygons by an angle around the
220
205
  image center.
221
206
 
222
207
  Args:
223
- ----
224
208
  geoms: (N, 4) or (N, 4, 2) array of ABSOLUTE coordinate boxes
225
209
  angle: anti-clockwise rotation angle in degrees
226
210
  img_shape: the height and width of the image
227
211
  expand: whether the image should be padded to avoid information loss
228
212
 
229
213
  Returns:
230
- -------
231
214
  A batch of rotated polygons (N, 4, 2)
232
215
  """
233
216
  # Switch to polygons
@@ -253,19 +236,17 @@ def rotate_abs_geoms(
253
236
  return rotated_polys
254
237
 
255
238
 
256
- def remap_boxes(loc_preds: np.ndarray, orig_shape: Tuple[int, int], dest_shape: Tuple[int, int]) -> np.ndarray:
239
+ def remap_boxes(loc_preds: np.ndarray, orig_shape: tuple[int, int], dest_shape: tuple[int, int]) -> np.ndarray:
257
240
  """Remaps a batch of rotated locpred (N, 4, 2) expressed for an origin_shape to a destination_shape.
258
241
  This does not impact the absolute shape of the boxes, but allow to calculate the new relative RotatedBbox
259
242
  coordinates after a resizing of the image.
260
243
 
261
244
  Args:
262
- ----
263
245
  loc_preds: (N, 4, 2) array of RELATIVE loc_preds
264
246
  orig_shape: shape of the origin image
265
247
  dest_shape: shape of the destination image
266
248
 
267
249
  Returns:
268
- -------
269
250
  A batch of rotated loc_preds (N, 4, 2) expressed in the destination referencial
270
251
  """
271
252
  if len(dest_shape) != 2:
@@ -284,9 +265,9 @@ def remap_boxes(loc_preds: np.ndarray, orig_shape: Tuple[int, int], dest_shape:
284
265
  def rotate_boxes(
285
266
  loc_preds: np.ndarray,
286
267
  angle: float,
287
- orig_shape: Tuple[int, int],
268
+ orig_shape: tuple[int, int],
288
269
  min_angle: float = 1.0,
289
- target_shape: Optional[Tuple[int, int]] = None,
270
+ target_shape: tuple[int, int] | None = None,
290
271
  ) -> np.ndarray:
291
272
  """Rotate a batch of straight bounding boxes (xmin, ymin, xmax, ymax, c) or rotated bounding boxes
292
273
  (4, 2) of an angle, if angle > min_angle, around the center of the page.
@@ -294,7 +275,6 @@ def rotate_boxes(
294
275
  is done to remove the padding that is created by rotate_page(expand=True)
295
276
 
296
277
  Args:
297
- ----
298
278
  loc_preds: (N, 4) or (N, 4, 2) array of RELATIVE boxes
299
279
  angle: angle between -90 and +90 degrees
300
280
  orig_shape: shape of the origin image
@@ -302,7 +282,6 @@ def rotate_boxes(
302
282
  target_shape: shape of the destination image
303
283
 
304
284
  Returns:
305
- -------
306
285
  A batch of rotated boxes (N, 4, 2): or a batch of straight bounding boxes
307
286
  """
308
287
  # Change format of the boxes to rotated boxes
@@ -349,20 +328,18 @@ def rotate_image(
349
328
  """Rotate an image counterclockwise by an given angle.
350
329
 
351
330
  Args:
352
- ----
353
331
  image: numpy tensor to rotate
354
332
  angle: rotation angle in degrees, between -90 and +90
355
333
  expand: whether the image should be padded before the rotation
356
334
  preserve_origin_shape: if expand is set to True, resizes the final output to the original image size
357
335
 
358
336
  Returns:
359
- -------
360
337
  Rotated array, padded by 0 by default.
361
338
  """
362
339
  # Compute the expanded padding
363
340
  exp_img: np.ndarray
364
341
  if expand:
365
- exp_shape = compute_expanded_shape(image.shape[:2], angle) # type: ignore[arg-type]
342
+ exp_shape = compute_expanded_shape(image.shape[:2], angle)
366
343
  h_pad, w_pad = (
367
344
  int(max(0, ceil(exp_shape[0] - image.shape[0]))),
368
345
  int(max(0, ceil(exp_shape[1] - image.shape[1]))),
@@ -383,7 +360,7 @@ def rotate_image(
383
360
  # Pad height
384
361
  else:
385
362
  h_pad, w_pad = int(rot_img.shape[1] * image.shape[0] / image.shape[1] - rot_img.shape[0]), 0
386
- rot_img = np.pad(rot_img, ((h_pad // 2, h_pad - h_pad // 2), (w_pad // 2, w_pad - w_pad // 2), (0, 0))) # type: ignore[assignment]
363
+ rot_img = np.pad(rot_img, ((h_pad // 2, h_pad - h_pad // 2), (w_pad // 2, w_pad - w_pad // 2), (0, 0)))
387
364
  if preserve_origin_shape:
388
365
  # rescale
389
366
  rot_img = cv2.resize(rot_img, image.shape[:-1][::-1], interpolation=cv2.INTER_LINEAR)
@@ -395,11 +372,9 @@ def remove_image_padding(image: np.ndarray) -> np.ndarray:
395
372
  """Remove black border padding from an image
396
373
 
397
374
  Args:
398
- ----
399
375
  image: numpy tensor to remove padding from
400
376
 
401
377
  Returns:
402
- -------
403
378
  Image with padding removed
404
379
  """
405
380
  # Find the bounding box of the non-black region
@@ -429,16 +404,14 @@ def estimate_page_angle(polys: np.ndarray) -> float:
429
404
  return 0.0
430
405
 
431
406
 
432
- def convert_to_relative_coords(geoms: np.ndarray, img_shape: Tuple[int, int]) -> np.ndarray:
407
+ def convert_to_relative_coords(geoms: np.ndarray, img_shape: tuple[int, int]) -> np.ndarray:
433
408
  """Convert a geometry to relative coordinates
434
409
 
435
410
  Args:
436
- ----
437
411
  geoms: a set of polygons of shape (N, 4, 2) or of straight boxes of shape (N, 4)
438
412
  img_shape: the height and width of the image
439
413
 
440
414
  Returns:
441
- -------
442
415
  the updated geometry
443
416
  """
444
417
  # Polygon
@@ -456,18 +429,16 @@ def convert_to_relative_coords(geoms: np.ndarray, img_shape: Tuple[int, int]) ->
456
429
  raise ValueError(f"invalid format for arg `geoms`: {geoms.shape}")
457
430
 
458
431
 
459
- def extract_crops(img: np.ndarray, boxes: np.ndarray, channels_last: bool = True) -> List[np.ndarray]:
432
+ def extract_crops(img: np.ndarray, boxes: np.ndarray, channels_last: bool = True) -> list[np.ndarray]:
460
433
  """Created cropped images from list of bounding boxes
461
434
 
462
435
  Args:
463
- ----
464
436
  img: input image
465
437
  boxes: bounding boxes of shape (N, 4) where N is the number of boxes, and the relative
466
438
  coordinates (xmin, ymin, xmax, ymax)
467
439
  channels_last: whether the channel dimensions is the last one instead of the last one
468
440
 
469
441
  Returns:
470
- -------
471
442
  list of cropped images
472
443
  """
473
444
  if boxes.shape[0] == 0:
@@ -492,11 +463,10 @@ def extract_crops(img: np.ndarray, boxes: np.ndarray, channels_last: bool = True
492
463
 
493
464
  def extract_rcrops(
494
465
  img: np.ndarray, polys: np.ndarray, dtype=np.float32, channels_last: bool = True, assume_horizontal: bool = False
495
- ) -> List[np.ndarray]:
466
+ ) -> list[np.ndarray]:
496
467
  """Created cropped images from list of rotated bounding boxes
497
468
 
498
469
  Args:
499
- ----
500
470
  img: input image
501
471
  polys: bounding boxes of shape (N, 4, 2)
502
472
  dtype: target data type of bounding boxes
@@ -504,7 +474,6 @@ def extract_rcrops(
504
474
  assume_horizontal: whether the boxes are assumed to be only horizontally oriented
505
475
 
506
476
  Returns:
507
- -------
508
477
  list of cropped images
509
478
  """
510
479
  if polys.shape[0] == 0:
@@ -603,4 +572,4 @@ def extract_rcrops(
603
572
  for idx in range(_boxes.shape[0])
604
573
  ]
605
574
 
606
- return crops # type: ignore[return-value]
575
+ return crops
@@ -6,15 +6,16 @@
6
6
 
7
7
  import multiprocessing as mp
8
8
  import os
9
+ from collections.abc import Callable, Iterable, Iterator
9
10
  from multiprocessing.pool import ThreadPool
10
- from typing import Any, Callable, Iterable, Iterator, Optional
11
+ from typing import Any
11
12
 
12
13
  from onnxtr.file_utils import ENV_VARS_TRUE_VALUES
13
14
 
14
15
  __all__ = ["multithread_exec"]
15
16
 
16
17
 
17
- def multithread_exec(func: Callable[[Any], Any], seq: Iterable[Any], threads: Optional[int] = None) -> Iterator[Any]:
18
+ def multithread_exec(func: Callable[[Any], Any], seq: Iterable[Any], threads: int | None = None) -> Iterator[Any]:
18
19
  """Execute a given function in parallel for each element of a given sequence
19
20
 
20
21
  >>> from onnxtr.utils.multithreading import multithread_exec
@@ -22,17 +23,14 @@ def multithread_exec(func: Callable[[Any], Any], seq: Iterable[Any], threads: Op
22
23
  >>> results = multithread_exec(lambda x: x ** 2, entries)
23
24
 
24
25
  Args:
25
- ----
26
26
  func: function to be executed on each element of the iterable
27
27
  seq: iterable
28
28
  threads: number of workers to be used for multiprocessing
29
29
 
30
30
  Returns:
31
- -------
32
31
  iterator of the function's results using the iterable as inputs
33
32
 
34
33
  Notes:
35
- -----
36
34
  This function uses ThreadPool from multiprocessing package, which uses `/dev/shm` directory for shared memory.
37
35
  If you do not have write permissions for this directory (if you run `onnxtr` on AWS Lambda for instance),
38
36
  you might want to disable multiprocessing. To achieve that, set 'ONNXTR_MULTIPROCESSING_DISABLE' to 'TRUE'.
@@ -3,7 +3,7 @@
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.
5
5
  import logging
6
- from typing import Any, Dict, Optional
6
+ from typing import Any
7
7
 
8
8
  import numpy as np
9
9
  from anyascii import anyascii
@@ -18,7 +18,7 @@ __all__ = ["synthesize_page"]
18
18
  ROTATION_WARNING = False
19
19
 
20
20
 
21
- def _warn_rotation(entry: Dict[str, Any]) -> None: # pragma: no cover
21
+ def _warn_rotation(entry: dict[str, Any]) -> None: # pragma: no cover
22
22
  global ROTATION_WARNING
23
23
  if not ROTATION_WARNING and len(entry["geometry"]) == 4:
24
24
  logging.warning("Polygons with larger rotations will lead to inaccurate rendering")
@@ -27,11 +27,11 @@ def _warn_rotation(entry: Dict[str, Any]) -> None: # pragma: no cover
27
27
 
28
28
  def _synthesize(
29
29
  response: Image.Image,
30
- entry: Dict[str, Any],
30
+ entry: dict[str, Any],
31
31
  w: int,
32
32
  h: int,
33
33
  draw_proba: bool = False,
34
- font_family: Optional[str] = None,
34
+ font_family: str | None = None,
35
35
  smoothing_factor: float = 0.75,
36
36
  min_font_size: int = 6,
37
37
  max_font_size: int = 50,
@@ -111,9 +111,9 @@ def _synthesize(
111
111
 
112
112
 
113
113
  def synthesize_page(
114
- page: Dict[str, Any],
114
+ page: dict[str, Any],
115
115
  draw_proba: bool = False,
116
- font_family: Optional[str] = None,
116
+ font_family: str | None = None,
117
117
  smoothing_factor: float = 0.95,
118
118
  min_font_size: int = 8,
119
119
  max_font_size: int = 50,
@@ -121,7 +121,6 @@ def synthesize_page(
121
121
  """Draw a the content of the element page (OCR response) on a blank page.
122
122
 
123
123
  Args:
124
- ----
125
124
  page: exported Page object to represent
126
125
  draw_proba: if True, draw words in colors to represent confidence. Blue: p=1, red: p=0
127
126
  font_family: family of the font
@@ -130,7 +129,6 @@ def synthesize_page(
130
129
  max_font_size: maximum font size
131
130
 
132
131
  Returns:
133
- -------
134
132
  the synthesized page
135
133
  """
136
134
  # Draw template
onnxtr/utils/repr.py CHANGED
@@ -5,7 +5,6 @@
5
5
 
6
6
  # Adapted from https://github.com/pytorch/torch/blob/master/torch/nn/modules/module.py
7
7
 
8
- from typing import List
9
8
 
10
9
  __all__ = ["NestedObject"]
11
10
 
@@ -25,7 +24,7 @@ def _addindent(s_, num_spaces):
25
24
  class NestedObject:
26
25
  """Base class for all nested objects in onnxtr"""
27
26
 
28
- _children_names: List[str]
27
+ _children_names: list[str]
29
28
 
30
29
  def extra_repr(self) -> str:
31
30
  return ""
@@ -4,7 +4,7 @@
4
4
  # See LICENSE or go to <https://opensource.org/licenses/Apache-2.0> for full license details.
5
5
 
6
6
  from copy import deepcopy
7
- from typing import Any, Dict, List, Optional, Tuple, Union
7
+ from typing import Any
8
8
 
9
9
  import cv2
10
10
  import matplotlib.patches as patches
@@ -19,9 +19,9 @@ __all__ = ["visualize_page", "draw_boxes"]
19
19
 
20
20
  def rect_patch(
21
21
  geometry: BoundingBox,
22
- page_dimensions: Tuple[int, int],
23
- label: Optional[str] = None,
24
- color: Tuple[float, float, float] = (0, 0, 0),
22
+ page_dimensions: tuple[int, int],
23
+ label: str | None = None,
24
+ color: tuple[float, float, float] = (0, 0, 0),
25
25
  alpha: float = 0.3,
26
26
  linewidth: int = 2,
27
27
  fill: bool = True,
@@ -30,7 +30,6 @@ def rect_patch(
30
30
  """Create a matplotlib rectangular patch for the element
31
31
 
32
32
  Args:
33
- ----
34
33
  geometry: bounding box of the element
35
34
  page_dimensions: dimensions of the Page in format (height, width)
36
35
  label: label to display when hovered
@@ -41,7 +40,6 @@ def rect_patch(
41
40
  preserve_aspect_ratio: pass True if you passed True to the predictor
42
41
 
43
42
  Returns:
44
- -------
45
43
  a rectangular Patch
46
44
  """
47
45
  if len(geometry) != 2 or any(not isinstance(elt, tuple) or len(elt) != 2 for elt in geometry):
@@ -70,9 +68,9 @@ def rect_patch(
70
68
 
71
69
  def polygon_patch(
72
70
  geometry: np.ndarray,
73
- page_dimensions: Tuple[int, int],
74
- label: Optional[str] = None,
75
- color: Tuple[float, float, float] = (0, 0, 0),
71
+ page_dimensions: tuple[int, int],
72
+ label: str | None = None,
73
+ color: tuple[float, float, float] = (0, 0, 0),
76
74
  alpha: float = 0.3,
77
75
  linewidth: int = 2,
78
76
  fill: bool = True,
@@ -81,7 +79,6 @@ def polygon_patch(
81
79
  """Create a matplotlib polygon patch for the element
82
80
 
83
81
  Args:
84
- ----
85
82
  geometry: bounding box of the element
86
83
  page_dimensions: dimensions of the Page in format (height, width)
87
84
  label: label to display when hovered
@@ -92,7 +89,6 @@ def polygon_patch(
92
89
  preserve_aspect_ratio: pass True if you passed True to the predictor
93
90
 
94
91
  Returns:
95
- -------
96
92
  a polygon Patch
97
93
  """
98
94
  if not geometry.shape == (4, 2):
@@ -114,20 +110,18 @@ def polygon_patch(
114
110
 
115
111
 
116
112
  def create_obj_patch(
117
- geometry: Union[BoundingBox, Polygon4P, np.ndarray],
118
- page_dimensions: Tuple[int, int],
113
+ geometry: BoundingBox | Polygon4P | np.ndarray,
114
+ page_dimensions: tuple[int, int],
119
115
  **kwargs: Any,
120
116
  ) -> patches.Patch:
121
117
  """Create a matplotlib patch for the element
122
118
 
123
119
  Args:
124
- ----
125
120
  geometry: bounding box (straight or rotated) of the element
126
121
  page_dimensions: dimensions of the page in format (height, width)
127
122
  **kwargs: keyword arguments for the patch
128
123
 
129
124
  Returns:
130
- -------
131
125
  a matplotlib Patch
132
126
  """
133
127
  if isinstance(geometry, tuple):
@@ -141,7 +135,7 @@ def create_obj_patch(
141
135
 
142
136
 
143
137
  def visualize_page(
144
- page: Dict[str, Any],
138
+ page: dict[str, Any],
145
139
  image: np.ndarray,
146
140
  words_only: bool = True,
147
141
  display_artefacts: bool = True,
@@ -163,7 +157,6 @@ def visualize_page(
163
157
  >>> plt.show()
164
158
 
165
159
  Args:
166
- ----
167
160
  page: the exported Page of a Document
168
161
  image: np array of the page, needs to have the same shape than page['dimensions']
169
162
  words_only: whether only words should be displayed
@@ -174,7 +167,6 @@ def visualize_page(
174
167
  **kwargs: keyword arguments for the polygon patch
175
168
 
176
169
  Returns:
177
- -------
178
170
  the matplotlib figure
179
171
  """
180
172
  # Get proper scale and aspect ratio
@@ -187,7 +179,7 @@ def visualize_page(
187
179
  ax.axis("off")
188
180
 
189
181
  if interactive:
190
- artists: List[patches.Patch] = [] # instantiate an empty list of patches (to be drawn on the page)
182
+ artists: list[patches.Patch] = [] # instantiate an empty list of patches (to be drawn on the page)
191
183
 
192
184
  for block in page["blocks"]:
193
185
  if not words_only:
@@ -266,11 +258,10 @@ def visualize_page(
266
258
  return fig
267
259
 
268
260
 
269
- def draw_boxes(boxes: np.ndarray, image: np.ndarray, color: Optional[Tuple[int, int, int]] = None, **kwargs) -> None:
261
+ def draw_boxes(boxes: np.ndarray, image: np.ndarray, color: tuple[int, int, int] | None = None, **kwargs) -> None:
270
262
  """Draw an array of relative straight boxes on an image
271
263
 
272
264
  Args:
273
- ----
274
265
  boxes: array of relative boxes, of shape (*, 4)
275
266
  image: np array, float32 or uint8
276
267
  color: color to use for bounding box edges
onnxtr/utils/vocabs.py CHANGED
@@ -4,12 +4,11 @@
4
4
  # See LICENSE or go to <https://opensource.org/licenses/Apache-2.0> for full license details.
5
5
 
6
6
  import string
7
- from typing import Dict
8
7
 
9
8
  __all__ = ["VOCABS"]
10
9
 
11
10
 
12
- VOCABS: Dict[str, str] = {
11
+ VOCABS: dict[str, str] = {
13
12
  "digits": string.digits,
14
13
  "ascii_letters": string.ascii_letters,
15
14
  "punctuation": string.punctuation,
onnxtr/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = 'v0.5.1'
1
+ __version__ = 'v0.6.0'