deepdoctection 0.42.1__py3-none-any.whl → 0.43__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of deepdoctection might be problematic. Click here for more details.

Files changed (124) hide show
  1. deepdoctection/__init__.py +2 -1
  2. deepdoctection/analyzer/__init__.py +2 -1
  3. deepdoctection/analyzer/config.py +904 -0
  4. deepdoctection/analyzer/dd.py +36 -62
  5. deepdoctection/analyzer/factory.py +311 -141
  6. deepdoctection/configs/conf_dd_one.yaml +100 -44
  7. deepdoctection/configs/profiles.jsonl +32 -0
  8. deepdoctection/dataflow/__init__.py +9 -6
  9. deepdoctection/dataflow/base.py +33 -15
  10. deepdoctection/dataflow/common.py +96 -75
  11. deepdoctection/dataflow/custom.py +36 -29
  12. deepdoctection/dataflow/custom_serialize.py +135 -91
  13. deepdoctection/dataflow/parallel_map.py +33 -31
  14. deepdoctection/dataflow/serialize.py +15 -10
  15. deepdoctection/dataflow/stats.py +41 -28
  16. deepdoctection/datapoint/__init__.py +4 -6
  17. deepdoctection/datapoint/annotation.py +104 -66
  18. deepdoctection/datapoint/box.py +190 -130
  19. deepdoctection/datapoint/convert.py +66 -39
  20. deepdoctection/datapoint/image.py +151 -95
  21. deepdoctection/datapoint/view.py +383 -236
  22. deepdoctection/datasets/__init__.py +2 -6
  23. deepdoctection/datasets/adapter.py +11 -11
  24. deepdoctection/datasets/base.py +118 -81
  25. deepdoctection/datasets/dataflow_builder.py +18 -12
  26. deepdoctection/datasets/info.py +76 -57
  27. deepdoctection/datasets/instances/__init__.py +6 -2
  28. deepdoctection/datasets/instances/doclaynet.py +17 -14
  29. deepdoctection/datasets/instances/fintabnet.py +16 -22
  30. deepdoctection/datasets/instances/funsd.py +11 -6
  31. deepdoctection/datasets/instances/iiitar13k.py +9 -9
  32. deepdoctection/datasets/instances/layouttest.py +9 -9
  33. deepdoctection/datasets/instances/publaynet.py +9 -9
  34. deepdoctection/datasets/instances/pubtables1m.py +13 -13
  35. deepdoctection/datasets/instances/pubtabnet.py +13 -15
  36. deepdoctection/datasets/instances/rvlcdip.py +8 -8
  37. deepdoctection/datasets/instances/xfund.py +11 -9
  38. deepdoctection/datasets/registry.py +18 -11
  39. deepdoctection/datasets/save.py +12 -11
  40. deepdoctection/eval/__init__.py +3 -2
  41. deepdoctection/eval/accmetric.py +72 -52
  42. deepdoctection/eval/base.py +29 -10
  43. deepdoctection/eval/cocometric.py +14 -12
  44. deepdoctection/eval/eval.py +56 -41
  45. deepdoctection/eval/registry.py +6 -3
  46. deepdoctection/eval/tedsmetric.py +24 -9
  47. deepdoctection/eval/tp_eval_callback.py +13 -12
  48. deepdoctection/extern/__init__.py +1 -1
  49. deepdoctection/extern/base.py +176 -97
  50. deepdoctection/extern/d2detect.py +127 -92
  51. deepdoctection/extern/deskew.py +19 -10
  52. deepdoctection/extern/doctrocr.py +157 -106
  53. deepdoctection/extern/fastlang.py +25 -17
  54. deepdoctection/extern/hfdetr.py +137 -60
  55. deepdoctection/extern/hflayoutlm.py +329 -248
  56. deepdoctection/extern/hflm.py +67 -33
  57. deepdoctection/extern/model.py +108 -762
  58. deepdoctection/extern/pdftext.py +37 -12
  59. deepdoctection/extern/pt/nms.py +15 -1
  60. deepdoctection/extern/pt/ptutils.py +13 -9
  61. deepdoctection/extern/tessocr.py +87 -54
  62. deepdoctection/extern/texocr.py +29 -14
  63. deepdoctection/extern/tp/tfutils.py +36 -8
  64. deepdoctection/extern/tp/tpcompat.py +54 -16
  65. deepdoctection/extern/tp/tpfrcnn/config/config.py +20 -4
  66. deepdoctection/extern/tpdetect.py +4 -2
  67. deepdoctection/mapper/__init__.py +1 -1
  68. deepdoctection/mapper/cats.py +117 -76
  69. deepdoctection/mapper/cocostruct.py +35 -17
  70. deepdoctection/mapper/d2struct.py +56 -29
  71. deepdoctection/mapper/hfstruct.py +32 -19
  72. deepdoctection/mapper/laylmstruct.py +221 -185
  73. deepdoctection/mapper/maputils.py +71 -35
  74. deepdoctection/mapper/match.py +76 -62
  75. deepdoctection/mapper/misc.py +68 -44
  76. deepdoctection/mapper/pascalstruct.py +13 -12
  77. deepdoctection/mapper/prodigystruct.py +33 -19
  78. deepdoctection/mapper/pubstruct.py +42 -32
  79. deepdoctection/mapper/tpstruct.py +39 -19
  80. deepdoctection/mapper/xfundstruct.py +20 -13
  81. deepdoctection/pipe/__init__.py +1 -2
  82. deepdoctection/pipe/anngen.py +104 -62
  83. deepdoctection/pipe/base.py +226 -107
  84. deepdoctection/pipe/common.py +206 -123
  85. deepdoctection/pipe/concurrency.py +74 -47
  86. deepdoctection/pipe/doctectionpipe.py +108 -47
  87. deepdoctection/pipe/language.py +41 -24
  88. deepdoctection/pipe/layout.py +45 -18
  89. deepdoctection/pipe/lm.py +146 -78
  90. deepdoctection/pipe/order.py +196 -113
  91. deepdoctection/pipe/refine.py +111 -63
  92. deepdoctection/pipe/registry.py +1 -1
  93. deepdoctection/pipe/segment.py +213 -142
  94. deepdoctection/pipe/sub_layout.py +76 -46
  95. deepdoctection/pipe/text.py +52 -33
  96. deepdoctection/pipe/transform.py +8 -6
  97. deepdoctection/train/d2_frcnn_train.py +87 -69
  98. deepdoctection/train/hf_detr_train.py +72 -40
  99. deepdoctection/train/hf_layoutlm_train.py +85 -46
  100. deepdoctection/train/tp_frcnn_train.py +56 -28
  101. deepdoctection/utils/concurrency.py +59 -16
  102. deepdoctection/utils/context.py +40 -19
  103. deepdoctection/utils/develop.py +25 -17
  104. deepdoctection/utils/env_info.py +85 -36
  105. deepdoctection/utils/error.py +16 -10
  106. deepdoctection/utils/file_utils.py +246 -62
  107. deepdoctection/utils/fs.py +162 -43
  108. deepdoctection/utils/identifier.py +29 -16
  109. deepdoctection/utils/logger.py +49 -32
  110. deepdoctection/utils/metacfg.py +83 -21
  111. deepdoctection/utils/pdf_utils.py +119 -62
  112. deepdoctection/utils/settings.py +24 -10
  113. deepdoctection/utils/tqdm.py +10 -5
  114. deepdoctection/utils/transform.py +182 -46
  115. deepdoctection/utils/utils.py +61 -28
  116. deepdoctection/utils/viz.py +150 -104
  117. deepdoctection-0.43.dist-info/METADATA +376 -0
  118. deepdoctection-0.43.dist-info/RECORD +149 -0
  119. deepdoctection/analyzer/_config.py +0 -146
  120. deepdoctection-0.42.1.dist-info/METADATA +0 -431
  121. deepdoctection-0.42.1.dist-info/RECORD +0 -148
  122. {deepdoctection-0.42.1.dist-info → deepdoctection-0.43.dist-info}/WHEEL +0 -0
  123. {deepdoctection-0.42.1.dist-info → deepdoctection-0.43.dist-info}/licenses/LICENSE +0 -0
  124. {deepdoctection-0.42.1.dist-info → deepdoctection-0.43.dist-info}/top_level.txt +0 -0
@@ -16,13 +16,7 @@
16
16
  # limitations under the License.
17
17
 
18
18
  """
19
- Some visualisation utils. Copied and pasted from
20
-
21
- <https://github.com/tensorpack/tensorpack/blob/master/tensorpack/utils/viz.py>
22
-
23
- and
24
-
25
- <https://github.com/facebookresearch/detectron2/blob/main/detectron2/utils/colormap.py>
19
+ Visualisation utils. Copied and pasted from
26
20
  """
27
21
 
28
22
  import base64
@@ -185,9 +179,12 @@ _COLORS = (
185
179
 
186
180
  def random_color(rgb: bool = True, maximum: int = 255) -> tuple[int, int, int]:
187
181
  """
188
- :param rgb: Whether to return RGB colors or BGR colors.
189
- :param maximum: either 255 or 1
190
- :return:
182
+ Args:
183
+ rgb: Whether to return RGB colors or BGR colors.
184
+ maximum: Either 255 or 1.
185
+
186
+ Returns:
187
+ A tuple of three integers representing the color.
191
188
  """
192
189
 
193
190
  idx = np.random.randint(0, len(_COLORS))
@@ -208,17 +205,24 @@ def draw_boxes(
208
205
  show_palette: bool = True,
209
206
  ) -> PixelValues:
210
207
  """
211
- Dray bounding boxes with category names into image.
212
-
213
- :param np_image: Image as np.ndarray
214
- :param boxes: A numpy array of shape Nx4 where each row is [x1, y1, x2, y2].
215
- :param category_names_list: List of N category names.
216
- :param color: A 3-tuple BGR color (in range [0, 255])
217
- :param font_scale: Font scale of text box
218
- :param rectangle_thickness: Thickness of bounding box
219
- :param box_color_by_category:
220
- :param show_palette: Whether to show a color palette of the categories
221
- :return: A new image np.ndarray
208
+ Draw bounding boxes with category names into image.
209
+
210
+ Args:
211
+ np_image: Image as `np.ndarray`.
212
+ boxes: A numpy array of shape Nx4 where each row is `[x1, y1, x2, y2]`.
213
+ category_names_list: List of N category names.
214
+ color: A 3-tuple BGR color (in range `[0, 255]`).
215
+ font_scale: Font scale of text box.
216
+ rectangle_thickness: Thickness of bounding box.
217
+ box_color_by_category: Whether to color boxes by category.
218
+ show_palette: Whether to show a color palette of the categories.
219
+
220
+ Returns:
221
+ A new image as `np.ndarray`.
222
+
223
+ Raises:
224
+ AssertionError: If the length of `category_names_list` does not match the number of boxes, or if any area is
225
+ not positive, or if boxes are out of image bounds.
222
226
  """
223
227
  if color is not None:
224
228
  box_color_by_category = False
@@ -284,9 +288,15 @@ def draw_boxes(
284
288
  @no_type_check
285
289
  def interactive_imshow(img: PixelValues) -> None:
286
290
  """
287
- Display an image in a pop-up window
291
+ Display an image in a pop-up window.
292
+
293
+ Args:
294
+ img: An image (expect BGR) to show.
288
295
 
289
- :param img: An image (expect BGR) to show.
296
+ Example:
297
+ ```python
298
+ interactive_imshow(img)
299
+ ```
290
300
  """
291
301
  viz_handler.interactive_imshow(img)
292
302
 
@@ -340,9 +350,15 @@ class VizPackageHandler:
340
350
  @staticmethod
341
351
  def _select_package() -> str:
342
352
  """
343
- USE_DD_OPENCV has priority and will enforce to use OpenCV
344
- Otherwise it will use Pillow as default package
345
- :return: either 'pillow' or 'cv2'
353
+ `USE_DD_OPENCV` has priority and will enforce to use OpenCV.
354
+ Otherwise it will use Pillow as default package.
355
+
356
+ Returns:
357
+ Either 'pillow' or 'cv2'.
358
+
359
+ Raises:
360
+ EnvironmentError: If both `USE_DD_OPENCV` and `USE_DD_PILLOW` are set to `False` or `True`.
361
+ DependencyError: If the required package is not available.
346
362
  """
347
363
  maybe_cv2 = "cv2" if os.environ.get("USE_DD_OPENCV", "False") in ENV_VARS_TRUE else None
348
364
  maybe_pil = "pillow" if os.environ.get("USE_DD_PILLOW", "True") in ENV_VARS_TRUE else None
@@ -378,23 +394,30 @@ class VizPackageHandler:
378
394
 
379
395
  def refresh(self) -> None:
380
396
  """
381
- Refresh the viz_handler setting. Useful if you change the env variable on run time and want to take account of
382
- the changes.
383
-
384
- **Example**
397
+ Refresh the `viz_handler` setting. Useful if you change the environment variable at runtime and want to take
398
+ account of the changes.
385
399
 
386
- os.env["USE_DD_OPENCV"]="True"
387
- viz_handler.refresh() # this will reset the original config and now use OpenCV
400
+ Example:
401
+ ```python
402
+ os.env["USE_DD_OPENCV"]="True"
403
+ viz_handler.refresh()
404
+ ```
388
405
 
389
- :return:
406
+ Returns:
407
+ None
390
408
  """
391
409
  package = self._select_package()
392
410
  self._set_vars(package)
393
411
 
394
412
  def read_image(self, path: PathLikeOrStr) -> PixelValues:
395
- """Reading an image from file and returning a np.array
413
+ """
414
+ Reading an image from file and returning a `np.array`.
396
415
 
397
- :param path: Use /path/to/dir/file_name.[suffix]
416
+ Args:
417
+ path: Use `/path/to/dir/file_name.[suffix]`.
418
+
419
+ Returns:
420
+ Image as `np.array`.
398
421
  """
399
422
  return getattr(self, self.pkg_func_dict["read_image"])(path)
400
423
 
@@ -409,10 +432,15 @@ class VizPackageHandler:
409
432
  return np_image
410
433
 
411
434
  def write_image(self, path: PathLikeOrStr, image: PixelValues) -> None:
412
- """Writing an image as np.array to a file.
435
+ """
436
+ Writing an image as `np.array` to a file.
413
437
 
414
- :param path: Use /path/to/dir/file_name.[suffix]
415
- :param image: pixel values as np.array
438
+ Args:
439
+ path: Use `/path/to/dir/file_name.[suffix]`.
440
+ image: Pixel values as `np.array`.
441
+
442
+ Returns:
443
+ None
416
444
  """
417
445
  return getattr(self, self.pkg_func_dict["write_image"])(path, image)
418
446
 
@@ -426,9 +454,14 @@ class VizPackageHandler:
426
454
  pil_image.save(os.fspath(path))
427
455
 
428
456
  def encode(self, np_image: PixelValues) -> bytes:
429
- """Converting an image as np.array into a b64 representation
457
+ """
458
+ Converting an image as `np.array` into a b64 representation.
459
+
460
+ Args:
461
+ np_image: Image as `np.array`.
430
462
 
431
- :param np_image: Image as np.array
463
+ Returns:
464
+ Image as bytes.
432
465
  """
433
466
  return getattr(self, self.pkg_func_dict["encode"])(np_image)
434
467
 
@@ -446,9 +479,14 @@ class VizPackageHandler:
446
479
  return buffered.getvalue()
447
480
 
448
481
  def convert_np_to_b64(self, image: PixelValues) -> str:
449
- """Converting an image given as np.array into a b64 encoded string
482
+ """
483
+ Converting an image given as `np.array` into a b64 encoded string.
484
+
485
+ Args:
486
+ image: Image as `np.array`.
450
487
 
451
- :param image: Image as np.array
488
+ Returns:
489
+ b64 encoded string.
452
490
  """
453
491
  return getattr(self, self.pkg_func_dict["convert_np_to_b64"])(image)
454
492
 
@@ -466,10 +504,13 @@ class VizPackageHandler:
466
504
 
467
505
  def convert_b64_to_np(self, image: B64Str) -> PixelValues:
468
506
  """
469
- Converting an image as b64 encoded string into np.array
507
+ Converting an image as b64 encoded string into `np.array`.
508
+
509
+ Args:
510
+ image: b64 encoded string.
470
511
 
471
- :param image: b64 encoded string
472
- :return: np.array
512
+ Returns:
513
+ `np.array`.
473
514
  """
474
515
  return getattr(self, self.pkg_func_dict["convert_b64_to_np"])(image)
475
516
 
@@ -487,32 +528,25 @@ class VizPackageHandler:
487
528
  return np.array(pil_image)[:, :, ::-1]
488
529
 
489
530
  def convert_bytes_to_np(self, image_bytes: bytes) -> PixelValues:
490
- """Converting an image as bytes into np.array
531
+ """
532
+ Converting an image as bytes into `np.array`.
533
+
534
+ Args:
535
+ image_bytes: Image as bytes.
491
536
 
492
- :param image_bytes: Image as np.array
537
+ Returns:
538
+ Image as `np.array`.
493
539
  """
494
540
  return getattr(self, self.pkg_func_dict["convert_bytes_to_np"])(image_bytes)
495
541
 
496
542
  @staticmethod
497
543
  def _cv2_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
498
- """
499
- Convert image bytes to a numpy array using OpenCV.
500
-
501
- :param image_bytes: Image bytes
502
- :return: Image as numpy array
503
- """
504
544
  np_array = np.frombuffer(image_bytes, np.uint8)
505
545
  np_image = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
506
546
  return np_image
507
547
 
508
548
  @staticmethod
509
549
  def _pillow_convert_bytes_to_np(image_bytes: bytes) -> PixelValues:
510
- """
511
- Convert image bytes to a numpy array using Pillow.
512
-
513
- :param image_bytes: Image bytes
514
- :return: Image as numpy array
515
- """
516
550
  image = Image.open(BytesIO(image_bytes))
517
551
  np_image = np.array(image)
518
552
  return np_image
@@ -520,16 +554,19 @@ class VizPackageHandler:
520
554
  def resize(self, image: PixelValues, width: int, height: int, interpolation: str) -> PixelValues:
521
555
  """
522
556
  Resize a given image to new width, height. Specifying an interpolation method is required. Depending on the
523
- chosen image library use one of the following:
557
+ chosen image library use one of the following:
524
558
 
525
559
  PIL: NEAREST, BOX, BILINEAR, BICUBIC, VIZ (available for CV2 as well)
526
560
  CV2: INTER_NEAREST, INTER_LINEAR, INTER_AREA, VIZ
527
561
 
528
- :param image: image as np.array
529
- :param width: the new image width
530
- :param height: the new image height
531
- :param interpolation: interpolation method as string.
532
- :return: resized image as np.array
562
+ Args:
563
+ image: Image as `np.array`.
564
+ width: The new image width.
565
+ height: The new image height.
566
+ interpolation: Interpolation method as string.
567
+
568
+ Returns:
569
+ Resized image as `np.array`.
533
570
  """
534
571
  return getattr(self, self.pkg_func_dict["resize"])(image, width, height, interpolation)
535
572
 
@@ -562,10 +599,14 @@ class VizPackageHandler:
562
599
 
563
600
  def get_text_size(self, text: str, font_scale: float) -> tuple[int, int]:
564
601
  """
565
- Return the text size for a given font scale
566
- :param text: text as string
567
- :param font_scale: scale
568
- :return: A tuple with width and height of the text
602
+ Return the text size for a given font scale.
603
+
604
+ Args:
605
+ text: Text as string.
606
+ font_scale: Scale.
607
+
608
+ Returns:
609
+ A tuple with width and height of the text.
569
610
  """
570
611
  return getattr(self, self.pkg_func_dict["get_text_size"])(text, font_scale)
571
612
 
@@ -583,11 +624,14 @@ class VizPackageHandler:
583
624
  """
584
625
  Drawing a rectangle into an image with a given color (b,g,r) and given thickness.
585
626
 
586
- :param np_image: image
587
- :param box: box (x_min, y_min, x_max, y_max)
588
- :param color: (b,g,r) between 0 and 255
589
- :param thickness: pixel width of the rectangle lines
590
- :return: image with rectangle
627
+ Args:
628
+ np_image: Image.
629
+ box: Box (x_min, y_min, x_max, y_max).
630
+ color: (b,g,r) between 0 and 255.
631
+ thickness: Pixel width of the rectangle lines.
632
+
633
+ Returns:
634
+ Image with rectangle.
591
635
  """
592
636
  return getattr(self, self.pkg_func_dict["draw_rectangle"])(np_image, box, color, thickness)
593
637
 
@@ -618,16 +662,19 @@ class VizPackageHandler:
618
662
  rectangle_thickness: int = 1,
619
663
  ) -> PixelValues:
620
664
  """
621
- Drawing a text into a numpy image. The result will differ between PIL and CV2 (and will not look that good when
622
- using PIL).
623
-
624
- :param np_image: image
625
- :param pos: x_min, y_min position of the starting point of the text
626
- :param text: text string
627
- :param color: (b,g,r) between 0 and 255
628
- :param font_scale: scale of font. This will only be used within a OPenCV framework
629
- :param rectangle_thickness: thickness of the rectangle border
630
- :return: image with text
665
+ Drawing a text into a numpy image. The result will differ between PIL and CV2 (and will not look that good
666
+ when using PIL).
667
+
668
+ Args:
669
+ np_image: Image.
670
+ pos: x_min, y_min position of the starting point of the text.
671
+ text: Text string.
672
+ color: `(b,g,r)` between 0 and 255.
673
+ font_scale: Scale of font. This will only be used within an OpenCV framework.
674
+ rectangle_thickness: Thickness of the rectangle border.
675
+
676
+ Returns:
677
+ Image with text.
631
678
  """
632
679
  return getattr(self, self.pkg_func_dict["draw_text"])(
633
680
  np_image, pos, text, color, font_scale, rectangle_thickness
@@ -642,18 +689,6 @@ class VizPackageHandler:
642
689
  font_scale: float,
643
690
  rectangle_thickness: int,
644
691
  ) -> PixelValues:
645
- """
646
- Draw text on an image.
647
-
648
- :param np_image: image as np.ndarray
649
- :param pos: x_min, y_min position of the starting point of the text
650
- :param text: text string to draw
651
- :param color: a 3-tuple BGR color in [0, 255]
652
- :param font_scale: float
653
- :param rectangle_thickness: thickness of the rectangle border
654
- :return: numpy array
655
- """
656
-
657
692
  np_image = np_image.astype(np.uint8)
658
693
  x_0, y_0 = int(pos[0]), int(pos[1])
659
694
  # Compute text size.
@@ -686,7 +721,6 @@ class VizPackageHandler:
686
721
  font_scale: float, # pylint: disable=W0613
687
722
  rectangle_thickness: int, # pylint: disable=W0613
688
723
  ) -> PixelValues:
689
- """Draw a text in an image using PIL."""
690
724
  # using PIL default font size that does not scale to larger image sizes.
691
725
  # Compare with https://github.com/python-pillow/Pillow/issues/6622
692
726
  pil_image = Image.fromarray(np.uint8(np_image[:, :, ::-1]))
@@ -695,15 +729,18 @@ class VizPackageHandler:
695
729
  return np.array(pil_image)[:, :, ::-1]
696
730
 
697
731
  def interactive_imshow(self, np_image: PixelValues) -> None:
698
- """Displaying an image in a separate window"""
699
- return getattr(self, self.pkg_func_dict["interactive_imshow"])(np_image)
700
-
701
- def _cv2_interactive_imshow(self, np_image: PixelValues) -> None:
702
732
  """
703
- Display an image in a pop-up window
733
+ Displaying an image in a separate window.
734
+
735
+ Args:
736
+ np_image: Image as `np.array`.
704
737
 
705
- :param img: An image (expect BGR) to show.
738
+ Returns:
739
+ None
706
740
  """
741
+ return getattr(self, self.pkg_func_dict["interactive_imshow"])(np_image)
742
+
743
+ def _cv2_interactive_imshow(self, np_image: PixelValues) -> None:
707
744
  name = "q, x: quit / s: save"
708
745
  cv2.imshow(name, np_image)
709
746
 
@@ -732,7 +769,16 @@ class VizPackageHandler:
732
769
  pil_image.show(name)
733
770
 
734
771
  def rotate_image(self, np_image: PixelValues, angle: float) -> PixelValues:
735
- """Rotating an image by some angle"""
772
+ """
773
+ Rotating an image by some angle.
774
+
775
+ Args:
776
+ np_image: Image as `np.array`.
777
+ angle: Angle to rotate.
778
+
779
+ Returns:
780
+ Rotated image as `np.array`.
781
+ """
736
782
  return getattr(self, self.pkg_func_dict["rotate_image"])(np_image, angle)
737
783
 
738
784
  @staticmethod