jdeskew 0.2.3__tar.gz → 0.3.0__tar.gz

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 (35) hide show
  1. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/python-package.yml +1 -1
  2. {jdeskew-0.2.3 → jdeskew-0.3.0}/PKG-INFO +3 -2
  3. jdeskew-0.3.0/icip_paper.pdf +0 -0
  4. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew/estimator.py +30 -26
  5. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew.egg-info/PKG-INFO +3 -2
  6. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew.egg-info/SOURCES.txt +1 -0
  7. {jdeskew-0.2.3 → jdeskew-0.3.0}/.circleci/config.yml +0 -0
  8. {jdeskew-0.2.3 → jdeskew-0.3.0}/.dockerignore +0 -0
  9. {jdeskew-0.2.3 → jdeskew-0.3.0}/.flake8 +0 -0
  10. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/codeql-analysis.yml +0 -0
  11. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/dependency-review.yml +0 -0
  12. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/docker-build-and-push.yml +0 -0
  13. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/greetings.yml +0 -0
  14. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/label.yml +0 -0
  15. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/python-publish.yml +0 -0
  16. {jdeskew-0.2.3 → jdeskew-0.3.0}/.github/workflows/stale.yml +0 -0
  17. {jdeskew-0.2.3 → jdeskew-0.3.0}/.gitignore +0 -0
  18. {jdeskew-0.2.3 → jdeskew-0.3.0}/.pre-commit-config.yaml +0 -0
  19. {jdeskew-0.2.3 → jdeskew-0.3.0}/Dockerfile +0 -0
  20. {jdeskew-0.2.3 → jdeskew-0.3.0}/LICENSE +0 -0
  21. {jdeskew-0.2.3 → jdeskew-0.3.0}/README.md +0 -0
  22. {jdeskew-0.2.3 → jdeskew-0.3.0}/cog.yaml +0 -0
  23. {jdeskew-0.2.3 → jdeskew-0.3.0}/estimator.py +0 -0
  24. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew/__init__.py +0 -0
  25. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew/utility.py +0 -0
  26. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew.egg-info/dependency_links.txt +0 -0
  27. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew.egg-info/requires.txt +0 -0
  28. {jdeskew-0.2.3 → jdeskew-0.3.0}/jdeskew.egg-info/top_level.txt +0 -0
  29. {jdeskew-0.2.3 → jdeskew-0.3.0}/main.py +0 -0
  30. {jdeskew-0.2.3 → jdeskew-0.3.0}/pyproject.toml +0 -0
  31. {jdeskew-0.2.3 → jdeskew-0.3.0}/reproduce.ipynb +0 -0
  32. {jdeskew-0.2.3 → jdeskew-0.3.0}/setup.cfg +0 -0
  33. {jdeskew-0.2.3 → jdeskew-0.3.0}/setup.py +0 -0
  34. {jdeskew-0.2.3 → jdeskew-0.3.0}/tests/test.png +0 -0
  35. {jdeskew-0.2.3 → jdeskew-0.3.0}/tests/test.py +0 -0
@@ -15,7 +15,7 @@ jobs:
15
15
  strategy:
16
16
  fail-fast: false
17
17
  matrix:
18
- python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
18
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
19
19
 
20
20
  steps:
21
21
  - uses: actions/checkout@v3
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: jdeskew
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Document Image Skew Estimation using Adaptive Radial Projection
5
5
  Author-email: Luan Pham <phamquiluan@gmail.com>
6
6
  License: MIT License
@@ -38,6 +38,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
38
38
  Requires-Dist: fastapi; extra == "dev"
39
39
  Requires-Dist: uvicorn[standard]; extra == "dev"
40
40
  Requires-Dist: python-multipart; extra == "dev"
41
+ Dynamic: license-file
41
42
 
42
43
  # Document Image Skew Estimation
43
44
 
Binary file
@@ -1,9 +1,10 @@
1
1
  """Skew Estimator."""
2
2
  import cv2
3
3
  import numpy as np
4
+ from typing import Optional
4
5
 
5
6
 
6
- def _ensure_gray(image):
7
+ def _ensure_gray(image: np.ndarray) -> np.ndarray:
7
8
  try:
8
9
  image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
9
10
  except cv2.error:
@@ -11,7 +12,7 @@ def _ensure_gray(image):
11
12
  return image
12
13
 
13
14
 
14
- def _ensure_optimal_square(image):
15
+ def _ensure_optimal_square(image: np.ndarray) -> np.ndarray:
15
16
  assert image is not None, image
16
17
  nw = nh = cv2.getOptimalDFTSize(max(image.shape[:2]))
17
18
  output_image = cv2.copyMakeBorder(
@@ -26,7 +27,7 @@ def _ensure_optimal_square(image):
26
27
  return output_image
27
28
 
28
29
 
29
- def _get_fft_magnitude(image):
30
+ def _get_fft_magnitude(image: np.ndarray) -> np.ndarray:
30
31
  gray = _ensure_gray(image)
31
32
  opt_gray = _ensure_optimal_square(gray)
32
33
 
@@ -35,7 +36,7 @@ def _get_fft_magnitude(image):
35
36
  ~opt_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, -10
36
37
  )
37
38
 
38
- # perform fft
39
+ # perform fft - using fft2 to ensure square output
39
40
  dft = np.fft.fft2(opt_gray)
40
41
  shifted_dft = np.fft.fftshift(dft)
41
42
 
@@ -44,7 +45,7 @@ def _get_fft_magnitude(image):
44
45
  return magnitude
45
46
 
46
47
 
47
- def _get_angle_radial_projection(m, angle_max=None, num=None, W=None):
48
+ def _get_angle_radial_projection(m: np.ndarray, angle_max: Optional[float] = None, num: Optional[int] = None) -> float:
48
49
  """Get angle via radial projection.
49
50
 
50
51
  Arguments:
@@ -57,42 +58,45 @@ def _get_angle_radial_projection(m, angle_max=None, num=None, W=None):
57
58
  r = c = m.shape[0] // 2
58
59
 
59
60
  if angle_max is None:
60
- pass
61
+ angle_max = 15.0
61
62
 
62
63
  if num is None:
63
64
  num = 20
64
65
 
65
66
  tr = np.linspace(-1 * angle_max, angle_max, int(angle_max * num * 2)) / 180 * np.pi
66
- profile_arr = tr.copy()
67
67
 
68
- def f(t):
69
- _f = np.vectorize(
70
- lambda x: m[c + int(x * np.cos(t)), c + int(-1 * x * np.sin(t))]
71
- )
72
- _l = _f(range(0, r))
73
- val_init = np.sum(_l)
74
- return val_init
68
+ # Pre-allocate array for better performance
69
+ li = np.zeros_like(tr)
75
70
 
76
- vf = np.vectorize(f)
77
- li = vf(profile_arr)
71
+ for i, t in enumerate(tr):
72
+ x = np.arange(0, r)
73
+ y = c + np.int32(x * np.cos(t))
74
+ x = c + np.int32(-1 * x * np.sin(t))
75
+ # Use boolean indexing for faster computation
76
+ valid_indices = (y >= 0) & (y < m.shape[0]) & (x >= 0) & (x < m.shape[1])
77
+ li[i] = np.sum(m[y[valid_indices], x[valid_indices]])
78
78
 
79
79
  a = tr[np.argmax(li)] / np.pi * 180
80
80
 
81
81
  if a == -1 * angle_max:
82
- return 0
83
- return a
82
+ return 0.0
83
+ return float(a)
84
84
 
85
85
 
86
86
  def get_angle(
87
- image: np.ndarray, vertical_image_shape: int = None, angle_max: float = None
88
- ):
87
+ image: np.ndarray,
88
+ vertical_image_shape: Optional[int] = None,
89
+ angle_max: Optional[float] = None
90
+ ) -> float:
89
91
  """Getting angle from a given document image.
90
92
 
91
- image : np.ndarray
92
- vertical_image_shape : int
93
- resize image as preprocessing
94
- angle_max : float
95
- maximum angle to searching
93
+ Args:
94
+ image: Input image as numpy array
95
+ vertical_image_shape: Optional resize height for preprocessing
96
+ angle_max: Maximum angle to search for
97
+
98
+ Returns:
99
+ float: Estimated skew angle in degrees
96
100
  """
97
101
  assert isinstance(image, np.ndarray), image
98
102
 
@@ -100,7 +104,7 @@ def get_angle(
100
104
  # vertical_image_shape = 512
101
105
 
102
106
  if angle_max is None:
103
- angle_max = 15
107
+ angle_max = 15.0
104
108
 
105
109
  # resize
106
110
  if vertical_image_shape is not None:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: jdeskew
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Document Image Skew Estimation using Adaptive Radial Projection
5
5
  Author-email: Luan Pham <phamquiluan@gmail.com>
6
6
  License: MIT License
@@ -38,6 +38,7 @@ Requires-Dist: pytest-xdist; extra == "dev"
38
38
  Requires-Dist: fastapi; extra == "dev"
39
39
  Requires-Dist: uvicorn[standard]; extra == "dev"
40
40
  Requires-Dist: python-multipart; extra == "dev"
41
+ Dynamic: license-file
41
42
 
42
43
  # Document Image Skew Estimation
43
44
 
@@ -7,6 +7,7 @@ LICENSE
7
7
  README.md
8
8
  cog.yaml
9
9
  estimator.py
10
+ icip_paper.pdf
10
11
  main.py
11
12
  pyproject.toml
12
13
  reproduce.ipynb
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes