jdeskew 0.2.2__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.2 → jdeskew-0.3.0}/.circleci/config.yml +1 -1
  2. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/python-package.yml +1 -1
  3. {jdeskew-0.2.2 → jdeskew-0.3.0}/PKG-INFO +20 -5
  4. {jdeskew-0.2.2 → jdeskew-0.3.0}/README.md +6 -2
  5. jdeskew-0.3.0/icip_paper.pdf +0 -0
  6. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew/estimator.py +30 -26
  7. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew/utility.py +5 -3
  8. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew.egg-info/PKG-INFO +20 -5
  9. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew.egg-info/SOURCES.txt +1 -0
  10. {jdeskew-0.2.2 → jdeskew-0.3.0}/tests/test.py +0 -2
  11. {jdeskew-0.2.2 → jdeskew-0.3.0}/.dockerignore +0 -0
  12. {jdeskew-0.2.2 → jdeskew-0.3.0}/.flake8 +0 -0
  13. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/codeql-analysis.yml +0 -0
  14. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/dependency-review.yml +0 -0
  15. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/docker-build-and-push.yml +0 -0
  16. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/greetings.yml +0 -0
  17. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/label.yml +0 -0
  18. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/python-publish.yml +0 -0
  19. {jdeskew-0.2.2 → jdeskew-0.3.0}/.github/workflows/stale.yml +0 -0
  20. {jdeskew-0.2.2 → jdeskew-0.3.0}/.gitignore +0 -0
  21. {jdeskew-0.2.2 → jdeskew-0.3.0}/.pre-commit-config.yaml +0 -0
  22. {jdeskew-0.2.2 → jdeskew-0.3.0}/Dockerfile +0 -0
  23. {jdeskew-0.2.2 → jdeskew-0.3.0}/LICENSE +0 -0
  24. {jdeskew-0.2.2 → jdeskew-0.3.0}/cog.yaml +0 -0
  25. {jdeskew-0.2.2 → jdeskew-0.3.0}/estimator.py +0 -0
  26. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew/__init__.py +0 -0
  27. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew.egg-info/dependency_links.txt +0 -0
  28. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew.egg-info/requires.txt +0 -0
  29. {jdeskew-0.2.2 → jdeskew-0.3.0}/jdeskew.egg-info/top_level.txt +0 -0
  30. {jdeskew-0.2.2 → jdeskew-0.3.0}/main.py +0 -0
  31. {jdeskew-0.2.2 → jdeskew-0.3.0}/pyproject.toml +0 -0
  32. {jdeskew-0.2.2 → jdeskew-0.3.0}/reproduce.ipynb +0 -0
  33. {jdeskew-0.2.2 → jdeskew-0.3.0}/setup.cfg +0 -0
  34. {jdeskew-0.2.2 → jdeskew-0.3.0}/setup.py +0 -0
  35. {jdeskew-0.2.2 → jdeskew-0.3.0}/tests/test.png +0 -0
@@ -8,7 +8,7 @@ executors:
8
8
  docker:
9
9
  - image: cimg/python:3.9
10
10
  environment:
11
- TZ: "Asia/Ho_Chi_Minh"
11
+ TZ: "Australia/Melbourne"
12
12
 
13
13
  jobs:
14
14
  build-and-test:
@@ -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.2
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
@@ -26,13 +26,22 @@ License: MIT License
26
26
  SOFTWARE.
27
27
 
28
28
  Description-Content-Type: text/markdown
29
- Provides-Extra: dev
30
29
  License-File: LICENSE
30
+ Requires-Dist: numpy
31
+ Requires-Dist: opencv-python-headless
32
+ Provides-Extra: dev
33
+ Requires-Dist: black; extra == "dev"
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Requires-Dist: coverage; extra == "dev"
36
+ Requires-Dist: pre-commit; extra == "dev"
37
+ Requires-Dist: pytest-xdist; extra == "dev"
38
+ Requires-Dist: fastapi; extra == "dev"
39
+ Requires-Dist: uvicorn[standard]; extra == "dev"
40
+ Requires-Dist: python-multipart; extra == "dev"
41
+ Dynamic: license-file
31
42
 
32
43
  # Document Image Skew Estimation
33
44
 
34
- *To my love, Jenna*
35
-
36
45
  [![pypi package](https://img.shields.io/pypi/v/jdeskew.svg)](https://pypi.org/project/jdeskew)
37
46
  [![CircleCI](https://dl.circleci.com/status-badge/img/gh/phamquiluan/jdeskew/tree/master.svg?style=svg&circle-token=f409daaab0e6671c81bb4b266b387fe933c131eb)](https://dl.circleci.com/status-badge/redirect/gh/phamquiluan/jdeskew/tree/master)
38
47
  [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/25553a5195074e37a01dd3370c55abaa)](https://www.codacy.com/gh/phamquiluan/jdeskew/dashboard?utm_source=github.com&utm_medium=referral&utm_content=phamquiluan/jdeskew&utm_campaign=Badge_Coverage)
@@ -153,6 +162,8 @@ This datasets are built upon three other datasets: DISEC 2013, RVL-CDIP, RDCL 20
153
162
  | DISE 2021 (45 degree) | https://drive.google.com/file/d/1a-a6aOqdsghjeHGLnCLsDs7NoJIus-Pw/view?usp=sharing |
154
163
  | DISE 2021 (15 degree) | https://drive.google.com/file/d/1BLiuu-j28dbuPFi4n3C0KuV6vXGmB0qS/view?usp=sharing |
155
164
 
165
+ Can also download from Zenodo: https://zenodo.org/records/12570649
166
+
156
167
  ## Reproducibility and Evaluation Code
157
168
 
158
169
  Check the [reproduce.ipynb](reproduce.ipynb) file
@@ -170,3 +181,7 @@ L. Pham, H. Hoang, X.T. Mai, T. A. Tran, "Adaptive Radial Projection on Fourier
170
181
  organization={IEEE}
171
182
  }
172
183
  ```
184
+
185
+ ## Star History
186
+
187
+ [![Star History Chart](https://api.star-history.com/svg?repos=phamquiluan/jdeskew&type=Date)](https://star-history.com/#phamquiluan/jdeskew&Date)
@@ -1,7 +1,5 @@
1
1
  # Document Image Skew Estimation
2
2
 
3
- *To my love, Jenna*
4
-
5
3
  [![pypi package](https://img.shields.io/pypi/v/jdeskew.svg)](https://pypi.org/project/jdeskew)
6
4
  [![CircleCI](https://dl.circleci.com/status-badge/img/gh/phamquiluan/jdeskew/tree/master.svg?style=svg&circle-token=f409daaab0e6671c81bb4b266b387fe933c131eb)](https://dl.circleci.com/status-badge/redirect/gh/phamquiluan/jdeskew/tree/master)
7
5
  [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/25553a5195074e37a01dd3370c55abaa)](https://www.codacy.com/gh/phamquiluan/jdeskew/dashboard?utm_source=github.com&utm_medium=referral&utm_content=phamquiluan/jdeskew&utm_campaign=Badge_Coverage)
@@ -122,6 +120,8 @@ This datasets are built upon three other datasets: DISEC 2013, RVL-CDIP, RDCL 20
122
120
  | DISE 2021 (45 degree) | https://drive.google.com/file/d/1a-a6aOqdsghjeHGLnCLsDs7NoJIus-Pw/view?usp=sharing |
123
121
  | DISE 2021 (15 degree) | https://drive.google.com/file/d/1BLiuu-j28dbuPFi4n3C0KuV6vXGmB0qS/view?usp=sharing |
124
122
 
123
+ Can also download from Zenodo: https://zenodo.org/records/12570649
124
+
125
125
  ## Reproducibility and Evaluation Code
126
126
 
127
127
  Check the [reproduce.ipynb](reproduce.ipynb) file
@@ -139,3 +139,7 @@ L. Pham, H. Hoang, X.T. Mai, T. A. Tran, "Adaptive Radial Projection on Fourier
139
139
  organization={IEEE}
140
140
  }
141
141
  ```
142
+
143
+ ## Star History
144
+
145
+ [![Star History Chart](https://api.star-history.com/svg?repos=phamquiluan/jdeskew&type=Date)](https://star-history.com/#phamquiluan/jdeskew&Date)
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:
@@ -2,7 +2,7 @@
2
2
  import cv2
3
3
 
4
4
 
5
- def rotate(image, angle, resize=True, border_mode=None, border_value=None):
5
+ def rotate(image, angle, resize=True, border_mode=None, border_value=None, flags=None):
6
6
  """Rotate input image respect to a given angle.
7
7
 
8
8
  Params:
@@ -13,6 +13,9 @@ def rotate(image, angle, resize=True, border_mode=None, border_value=None):
13
13
  """
14
14
  if border_mode is None:
15
15
  border_mode = cv2.BORDER_CONSTANT
16
+ if flags is None:
17
+ # flags=cv2.INTER_NEAREST
18
+ flags = cv2.INTER_LINEAR
16
19
 
17
20
  h, w = image.shape[:2]
18
21
  M = cv2.getRotationMatrix2D(center=(w // 2, h // 2), angle=angle, scale=1.0)
@@ -20,8 +23,7 @@ def rotate(image, angle, resize=True, border_mode=None, border_value=None):
20
23
  src=image,
21
24
  M=M,
22
25
  dsize=(w, h),
23
- # flags=cv2.INTER_CUBIC,
24
- flags=cv2.INTER_NEAREST,
26
+ flags=flags,
25
27
  borderMode=border_mode,
26
28
  borderValue=None if border_mode == cv2.BORDER_REPLICATE else border_value,
27
29
  )
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: jdeskew
3
- Version: 0.2.2
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
@@ -26,13 +26,22 @@ License: MIT License
26
26
  SOFTWARE.
27
27
 
28
28
  Description-Content-Type: text/markdown
29
- Provides-Extra: dev
30
29
  License-File: LICENSE
30
+ Requires-Dist: numpy
31
+ Requires-Dist: opencv-python-headless
32
+ Provides-Extra: dev
33
+ Requires-Dist: black; extra == "dev"
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Requires-Dist: coverage; extra == "dev"
36
+ Requires-Dist: pre-commit; extra == "dev"
37
+ Requires-Dist: pytest-xdist; extra == "dev"
38
+ Requires-Dist: fastapi; extra == "dev"
39
+ Requires-Dist: uvicorn[standard]; extra == "dev"
40
+ Requires-Dist: python-multipart; extra == "dev"
41
+ Dynamic: license-file
31
42
 
32
43
  # Document Image Skew Estimation
33
44
 
34
- *To my love, Jenna*
35
-
36
45
  [![pypi package](https://img.shields.io/pypi/v/jdeskew.svg)](https://pypi.org/project/jdeskew)
37
46
  [![CircleCI](https://dl.circleci.com/status-badge/img/gh/phamquiluan/jdeskew/tree/master.svg?style=svg&circle-token=f409daaab0e6671c81bb4b266b387fe933c131eb)](https://dl.circleci.com/status-badge/redirect/gh/phamquiluan/jdeskew/tree/master)
38
47
  [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/25553a5195074e37a01dd3370c55abaa)](https://www.codacy.com/gh/phamquiluan/jdeskew/dashboard?utm_source=github.com&utm_medium=referral&utm_content=phamquiluan/jdeskew&utm_campaign=Badge_Coverage)
@@ -153,6 +162,8 @@ This datasets are built upon three other datasets: DISEC 2013, RVL-CDIP, RDCL 20
153
162
  | DISE 2021 (45 degree) | https://drive.google.com/file/d/1a-a6aOqdsghjeHGLnCLsDs7NoJIus-Pw/view?usp=sharing |
154
163
  | DISE 2021 (15 degree) | https://drive.google.com/file/d/1BLiuu-j28dbuPFi4n3C0KuV6vXGmB0qS/view?usp=sharing |
155
164
 
165
+ Can also download from Zenodo: https://zenodo.org/records/12570649
166
+
156
167
  ## Reproducibility and Evaluation Code
157
168
 
158
169
  Check the [reproduce.ipynb](reproduce.ipynb) file
@@ -170,3 +181,7 @@ L. Pham, H. Hoang, X.T. Mai, T. A. Tran, "Adaptive Radial Projection on Fourier
170
181
  organization={IEEE}
171
182
  }
172
183
  ```
184
+
185
+ ## Star History
186
+
187
+ [![Star History Chart](https://api.star-history.com/svg?repos=phamquiluan/jdeskew&type=Date)](https://star-history.com/#phamquiluan/jdeskew&Date)
@@ -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
@@ -19,7 +19,6 @@ def test_basic():
19
19
  def test_text_image_angle_range_10(angle: int):
20
20
  """Test_text_image_angle_range_10."""
21
21
  image = cv2.imread(path.join(path.dirname(__file__), "test.png"))
22
- # for angle in range(-10, 10):
23
22
  skew_image = rotate(image, angle=angle, resize=False)
24
23
  estimated_angle = get_angle(skew_image, vertical_image_shape=512)
25
24
  assert abs(angle + estimated_angle) < 0.5, f"{angle} - {estimated_angle}"
@@ -29,7 +28,6 @@ def test_text_image_angle_range_10(angle: int):
29
28
  def test_text_image_angle_range_44(angle: int):
30
29
  """Test_text_image_angle_range_44."""
31
30
  image = cv2.imread(path.join(path.dirname(__file__), "test.png"))
32
- # for angle in range(-44, 44):
33
31
  skew_image = rotate(image, angle=angle, resize=False)
34
32
  estimated_angle = get_angle(skew_image, vertical_image_shape=512, angle_max=44.9)
35
33
  assert abs(angle + estimated_angle) < 0.5, f"{angle} - {estimated_angle}"
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