ImagePRO-Python 0.1.0__py3-none-any.whl → 0.2.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.
- ImagePRO/human_analysis/body_analysis/body_pose_estimation.py +61 -57
- ImagePRO/human_analysis/body_analysis/hand_tracking.py +68 -73
- ImagePRO/human_analysis/face_analysis/eye_status_analysis.py +73 -43
- ImagePRO/human_analysis/face_analysis/face_detection.py +54 -29
- ImagePRO/human_analysis/face_analysis/face_mesh_analysis.py +131 -78
- ImagePRO/human_analysis/face_analysis/head_pose_estimation.py +68 -39
- ImagePRO/pre_processing/blur.py +134 -66
- ImagePRO/pre_processing/contrast.py +111 -63
- ImagePRO/pre_processing/crop.py +42 -17
- ImagePRO/pre_processing/grayscale.py +33 -11
- ImagePRO/pre_processing/resize.py +40 -19
- ImagePRO/pre_processing/rotate.py +92 -71
- ImagePRO/pre_processing/sharpen.py +54 -38
- ImagePRO/utils/__init__.py +0 -0
- ImagePRO/utils/io_handler.py +180 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/METADATA +1 -1
- imagepro_python-0.2.0.dist-info/RECORD +25 -0
- imagepro_python-0.1.0.dist-info/RECORD +0 -23
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/WHEEL +0 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {imagepro_python-0.1.0.dist-info → imagepro_python-0.2.0.dist-info}/top_level.txt +0 -0
ImagePRO/pre_processing/blur.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
4
3
|
import cv2
|
|
5
4
|
import numpy as np
|
|
6
5
|
|
|
@@ -8,24 +7,44 @@ import numpy as np
|
|
|
8
7
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
9
8
|
sys.path.append(str(parent_dir))
|
|
10
9
|
|
|
11
|
-
from io_handler import IOHandler
|
|
10
|
+
from utils.io_handler import IOHandler
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
def apply_average_blur(
|
|
13
|
+
def apply_average_blur(
|
|
14
|
+
kernel_size: tuple[int, int] = (5, 5),
|
|
15
|
+
src_image_path: str | None = None,
|
|
16
|
+
src_np_image=None,
|
|
17
|
+
output_image_path: str | None = None
|
|
18
|
+
) -> np.ndarray:
|
|
15
19
|
"""
|
|
16
20
|
Apply average blur (box filter) to an image.
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
kernel_size : tuple[int, int], default=(5, 5)
|
|
25
|
+
Blur kernel size (width, height). Both must be positive integers.
|
|
26
|
+
src_image_path : str | None, optional
|
|
27
|
+
Path to input image.
|
|
28
|
+
src_np_image : np.ndarray | None, optional
|
|
29
|
+
Preloaded BGR image array.
|
|
30
|
+
output_image_path : str | None, optional
|
|
31
|
+
If provided, save the blurred image.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
np.ndarray
|
|
36
|
+
Blurred image.
|
|
37
|
+
|
|
38
|
+
Raises
|
|
39
|
+
------
|
|
40
|
+
ValueError
|
|
41
|
+
If kernel size is invalid.
|
|
42
|
+
TypeError
|
|
43
|
+
If input types are invalid.
|
|
44
|
+
FileNotFoundError
|
|
45
|
+
If image path does not exist.
|
|
46
|
+
IOError
|
|
47
|
+
If saving the image fails.
|
|
29
48
|
"""
|
|
30
49
|
if (
|
|
31
50
|
not isinstance(kernel_size, tuple)
|
|
@@ -34,26 +53,42 @@ def apply_average_blur(kernel_size=(5, 5), image_path=None, np_image=None, resul
|
|
|
34
53
|
):
|
|
35
54
|
raise ValueError("'kernel_size' must be a tuple of two positive integers.")
|
|
36
55
|
|
|
37
|
-
np_image = IOHandler.load_image(image_path=
|
|
56
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
38
57
|
blurred = cv2.blur(np_image, kernel_size)
|
|
39
|
-
|
|
58
|
+
if output_image_path:
|
|
59
|
+
print(IOHandler.save_image(blurred, output_image_path))
|
|
60
|
+
return blurred
|
|
40
61
|
|
|
41
62
|
|
|
42
|
-
def apply_gaussian_blur(
|
|
63
|
+
def apply_gaussian_blur(
|
|
64
|
+
kernel_size: tuple[int, int] = (5, 5),
|
|
65
|
+
src_image_path: str | None = None,
|
|
66
|
+
src_np_image=None,
|
|
67
|
+
output_image_path: str | None = None
|
|
68
|
+
) -> np.ndarray:
|
|
43
69
|
"""
|
|
44
70
|
Apply Gaussian blur to an image.
|
|
45
71
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
kernel_size : tuple[int, int], default=(5, 5)
|
|
75
|
+
Kernel size (width, height), both odd positive integers.
|
|
76
|
+
src_image_path : str | None, optional
|
|
77
|
+
Path to input image.
|
|
78
|
+
src_np_image : np.ndarray | None, optional
|
|
79
|
+
Preloaded BGR image array.
|
|
80
|
+
output_image_path : str | None, optional
|
|
81
|
+
If provided, save the blurred image.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
np.ndarray
|
|
86
|
+
Blurred image.
|
|
87
|
+
|
|
88
|
+
Raises
|
|
89
|
+
------
|
|
90
|
+
ValueError
|
|
91
|
+
If kernel size is invalid.
|
|
57
92
|
"""
|
|
58
93
|
if (
|
|
59
94
|
not isinstance(kernel_size, tuple)
|
|
@@ -62,61 +97,92 @@ def apply_gaussian_blur(kernel_size=(5, 5), image_path=None, np_image=None, resu
|
|
|
62
97
|
):
|
|
63
98
|
raise ValueError("'kernel_size' must be a tuple of two odd positive integers.")
|
|
64
99
|
|
|
65
|
-
np_image = IOHandler.load_image(image_path=
|
|
100
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
66
101
|
blurred = cv2.GaussianBlur(np_image, kernel_size, sigmaX=0)
|
|
67
|
-
|
|
102
|
+
if output_image_path:
|
|
103
|
+
print(IOHandler.save_image(blurred, output_image_path))
|
|
104
|
+
return blurred
|
|
68
105
|
|
|
69
106
|
|
|
70
|
-
def apply_median_blur(
|
|
107
|
+
def apply_median_blur(
|
|
108
|
+
filter_size: int = 5,
|
|
109
|
+
src_image_path: str | None = None,
|
|
110
|
+
src_np_image=None,
|
|
111
|
+
output_image_path: str | None = None
|
|
112
|
+
) -> np.ndarray:
|
|
71
113
|
"""
|
|
72
114
|
Apply median blur to remove salt-and-pepper noise.
|
|
73
115
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
filter_size : int, default=5
|
|
119
|
+
Must be an odd integer greater than 1.
|
|
120
|
+
src_image_path : str | None, optional
|
|
121
|
+
Path to input image.
|
|
122
|
+
src_np_image : np.ndarray | None, optional
|
|
123
|
+
Preloaded BGR image array.
|
|
124
|
+
output_image_path : str | None, optional
|
|
125
|
+
If provided, save the blurred image.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
np.ndarray
|
|
130
|
+
Blurred image.
|
|
131
|
+
|
|
132
|
+
Raises
|
|
133
|
+
------
|
|
134
|
+
TypeError
|
|
135
|
+
If filter_size is not an integer.
|
|
136
|
+
ValueError
|
|
137
|
+
If filter_size is not an odd integer greater than 1.
|
|
85
138
|
"""
|
|
86
139
|
if not isinstance(filter_size, int):
|
|
87
140
|
raise TypeError("'filter_size' must be an integer.")
|
|
88
141
|
if filter_size <= 1 or filter_size % 2 == 0:
|
|
89
142
|
raise ValueError("'filter_size' must be an odd integer greater than 1.")
|
|
90
143
|
|
|
91
|
-
np_image = IOHandler.load_image(image_path=
|
|
144
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
92
145
|
blurred = cv2.medianBlur(np_image, filter_size)
|
|
93
|
-
|
|
146
|
+
if output_image_path:
|
|
147
|
+
print(IOHandler.save_image(blurred, output_image_path))
|
|
148
|
+
return blurred
|
|
94
149
|
|
|
95
150
|
|
|
96
151
|
def apply_bilateral_blur(
|
|
97
|
-
filter_size=9,
|
|
98
|
-
sigma_color=75,
|
|
99
|
-
sigma_space=75,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
):
|
|
152
|
+
filter_size: int = 9,
|
|
153
|
+
sigma_color: float = 75,
|
|
154
|
+
sigma_space: float = 75,
|
|
155
|
+
src_image_path: str | None = None,
|
|
156
|
+
src_np_image=None,
|
|
157
|
+
output_image_path: str | None = None
|
|
158
|
+
) -> np.ndarray:
|
|
104
159
|
"""
|
|
105
160
|
Apply bilateral filter to smooth while preserving edges.
|
|
106
161
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
filter_size : int, default=9
|
|
165
|
+
Diameter of pixel neighborhood.
|
|
166
|
+
sigma_color : float, default=75
|
|
167
|
+
Color-space standard deviation.
|
|
168
|
+
sigma_space : float, default=75
|
|
169
|
+
Coordinate-space standard deviation.
|
|
170
|
+
src_image_path : str | None, optional
|
|
171
|
+
Path to input image.
|
|
172
|
+
src_np_image : np.ndarray | None, optional
|
|
173
|
+
Preloaded BGR image array.
|
|
174
|
+
output_image_path : str | None, optional
|
|
175
|
+
If provided, save the blurred image.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
np.ndarray
|
|
180
|
+
Blurred image.
|
|
181
|
+
|
|
182
|
+
Raises
|
|
183
|
+
------
|
|
184
|
+
ValueError
|
|
185
|
+
If parameters are invalid.
|
|
120
186
|
"""
|
|
121
187
|
if not isinstance(filter_size, int) or filter_size < 1:
|
|
122
188
|
raise ValueError("'filter_size' must be a positive integer.")
|
|
@@ -125,6 +191,8 @@ def apply_bilateral_blur(
|
|
|
125
191
|
if not isinstance(sigma_space, (int, float)) or sigma_space <= 0:
|
|
126
192
|
raise ValueError("'sigma_space' must be a positive number.")
|
|
127
193
|
|
|
128
|
-
np_image = IOHandler.load_image(image_path=
|
|
194
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
129
195
|
blurred = cv2.bilateralFilter(np_image, filter_size, sigma_color, sigma_space)
|
|
130
|
-
|
|
196
|
+
if output_image_path:
|
|
197
|
+
print(IOHandler.save_image(blurred, output_image_path))
|
|
198
|
+
return blurred
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
4
3
|
import cv2
|
|
5
4
|
import numpy as np
|
|
6
5
|
|
|
@@ -9,89 +8,134 @@ parent_dir = Path(__file__).resolve().parent.parent
|
|
|
9
8
|
sys.path.append(str(parent_dir))
|
|
10
9
|
|
|
11
10
|
from pre_processing.grayscale import convert_to_grayscale
|
|
12
|
-
from io_handler import IOHandler
|
|
11
|
+
from utils.io_handler import IOHandler
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def apply_clahe_contrast(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
):
|
|
15
|
+
clip_limit: float = 2.0,
|
|
16
|
+
tile_grid_size: tuple[int, int] = (8, 8),
|
|
17
|
+
src_image_path: str | None = None,
|
|
18
|
+
src_np_image=None,
|
|
19
|
+
output_image_path: str | None = None
|
|
20
|
+
) -> np.ndarray:
|
|
22
21
|
"""
|
|
23
|
-
Enhance contrast using CLAHE (adaptive histogram equalization).
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
Enhance image contrast using CLAHE (adaptive histogram equalization).
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
clip_limit : float, default=2.0
|
|
27
|
+
Contrast threshold (must be > 0).
|
|
28
|
+
tile_grid_size : tuple[int, int], default=(8, 8)
|
|
29
|
+
Grid size for local histogram (positive integers).
|
|
30
|
+
src_image_path : str | None, optional
|
|
31
|
+
Path to input image.
|
|
32
|
+
src_np_image : np.ndarray | None, optional
|
|
33
|
+
Preloaded image.
|
|
34
|
+
output_image_path : str | None, optional
|
|
35
|
+
Path to save the enhanced image.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
np.ndarray
|
|
40
|
+
Enhanced grayscale image.
|
|
41
|
+
|
|
42
|
+
Raises
|
|
43
|
+
------
|
|
44
|
+
ValueError
|
|
45
|
+
If `clip_limit` <= 0.
|
|
46
|
+
TypeError
|
|
47
|
+
If `tile_grid_size` is not valid.
|
|
48
|
+
FileNotFoundError
|
|
49
|
+
If image path is invalid.
|
|
50
|
+
IOError
|
|
51
|
+
If saving the image fails.
|
|
37
52
|
"""
|
|
38
|
-
if not isinstance(
|
|
39
|
-
raise ValueError("'
|
|
53
|
+
if not isinstance(clip_limit, (int, float)) or clip_limit <= 0:
|
|
54
|
+
raise ValueError("'clip_limit' must be a positive number.")
|
|
40
55
|
|
|
41
56
|
if (
|
|
42
|
-
not isinstance(
|
|
43
|
-
or len(
|
|
44
|
-
or not all(isinstance(i, int) and i > 0 for i in
|
|
57
|
+
not isinstance(tile_grid_size, tuple)
|
|
58
|
+
or len(tile_grid_size) != 2
|
|
59
|
+
or not all(isinstance(i, int) and i > 0 for i in tile_grid_size)
|
|
45
60
|
):
|
|
46
|
-
raise TypeError("'
|
|
61
|
+
raise TypeError("'tile_grid_size' must be a tuple of two positive integers.")
|
|
47
62
|
|
|
48
|
-
np_image = convert_to_grayscale(
|
|
63
|
+
np_image = convert_to_grayscale(
|
|
64
|
+
np_image=IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
65
|
+
)
|
|
49
66
|
|
|
50
|
-
clahe = cv2.createCLAHE(clipLimit=
|
|
67
|
+
clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_grid_size)
|
|
51
68
|
enhanced = clahe.apply(np_image)
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
if output_image_path:
|
|
71
|
+
print(IOHandler.save_image(enhanced, output_image_path))
|
|
72
|
+
return enhanced
|
|
54
73
|
|
|
55
74
|
|
|
56
|
-
def apply_histogram_equalization(
|
|
75
|
+
def apply_histogram_equalization(
|
|
76
|
+
src_image_path: str | None = None,
|
|
77
|
+
src_np_image=None,
|
|
78
|
+
output_image_path: str | None = None
|
|
79
|
+
) -> np.ndarray:
|
|
57
80
|
"""
|
|
58
81
|
Enhance contrast using global histogram equalization.
|
|
59
82
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
src_image_path : str | None, optional
|
|
86
|
+
Path to input image.
|
|
87
|
+
src_np_image : np.ndarray | None, optional
|
|
88
|
+
Preloaded image.
|
|
89
|
+
output_image_path : str | None, optional
|
|
90
|
+
Path to save the enhanced image.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
np.ndarray
|
|
95
|
+
Enhanced grayscale image.
|
|
67
96
|
"""
|
|
68
|
-
np_image = convert_to_grayscale(
|
|
97
|
+
np_image = convert_to_grayscale(
|
|
98
|
+
np_image=IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
99
|
+
)
|
|
69
100
|
enhanced = cv2.equalizeHist(np_image)
|
|
70
|
-
|
|
101
|
+
|
|
102
|
+
if output_image_path:
|
|
103
|
+
print(IOHandler.save_image(enhanced, output_image_path))
|
|
104
|
+
return enhanced
|
|
71
105
|
|
|
72
106
|
|
|
73
107
|
def apply_contrast_stretching(
|
|
74
|
-
alpha,
|
|
75
|
-
beta,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
):
|
|
108
|
+
alpha: float,
|
|
109
|
+
beta: int,
|
|
110
|
+
src_image_path: str | None = None,
|
|
111
|
+
src_np_image=None,
|
|
112
|
+
output_image_path: str | None = None
|
|
113
|
+
) -> np.ndarray:
|
|
80
114
|
"""
|
|
81
|
-
Enhance contrast by linear
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
Enhance contrast by linear stretching: `alpha × pixel + beta`.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
alpha : float
|
|
120
|
+
Contrast factor (>= 0).
|
|
121
|
+
beta : int
|
|
122
|
+
Brightness offset (0–255).
|
|
123
|
+
src_image_path : str | None, optional
|
|
124
|
+
Path to input image.
|
|
125
|
+
src_np_image : np.ndarray | None, optional
|
|
126
|
+
Preloaded image.
|
|
127
|
+
output_image_path : str | None, optional
|
|
128
|
+
Path to save the enhanced image.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
np.ndarray
|
|
133
|
+
Enhanced grayscale image.
|
|
134
|
+
|
|
135
|
+
Raises
|
|
136
|
+
------
|
|
137
|
+
ValueError
|
|
138
|
+
If `alpha` or `beta` are out of range.
|
|
95
139
|
"""
|
|
96
140
|
if not isinstance(alpha, (int, float)) or alpha < 0:
|
|
97
141
|
raise ValueError("'alpha' must be a non-negative number.")
|
|
@@ -99,7 +143,11 @@ def apply_contrast_stretching(
|
|
|
99
143
|
if not isinstance(beta, int) or not (0 <= beta <= 255):
|
|
100
144
|
raise ValueError("'beta' must be an integer between 0 and 255.")
|
|
101
145
|
|
|
102
|
-
np_image = convert_to_grayscale(
|
|
146
|
+
np_image = convert_to_grayscale(
|
|
147
|
+
np_image=IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
148
|
+
)
|
|
103
149
|
enhanced = cv2.convertScaleAbs(np_image, alpha=alpha, beta=beta)
|
|
104
150
|
|
|
105
|
-
|
|
151
|
+
if output_image_path:
|
|
152
|
+
print(IOHandler.save_image(enhanced, output_image_path))
|
|
153
|
+
return enhanced
|
ImagePRO/pre_processing/crop.py
CHANGED
|
@@ -1,30 +1,52 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
import numpy as np
|
|
3
4
|
|
|
4
5
|
# Add parent directory to sys.path for importing custom modules
|
|
5
6
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
6
7
|
sys.path.append(str(parent_dir))
|
|
7
8
|
|
|
8
|
-
from io_handler import IOHandler
|
|
9
|
+
from utils.io_handler import IOHandler
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
def crop_image(
|
|
12
|
+
def crop_image(
|
|
13
|
+
start_point: tuple[int, int],
|
|
14
|
+
end_point: tuple[int, int],
|
|
15
|
+
src_image_path: str | None = None,
|
|
16
|
+
src_np_image: np.ndarray | None = None,
|
|
17
|
+
output_image_path: str | None = None
|
|
18
|
+
) -> np.ndarray:
|
|
12
19
|
"""
|
|
13
|
-
Crop image using top-left and bottom-right coordinates.
|
|
20
|
+
Crop an image using top-left and bottom-right coordinates.
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
start_point : tuple[int, int]
|
|
25
|
+
(x1, y1) coordinates of the top-left corner.
|
|
26
|
+
end_point : tuple[int, int]
|
|
27
|
+
(x2, y2) coordinates of the bottom-right corner.
|
|
28
|
+
src_image_path : str | None, optional
|
|
29
|
+
Path to input image. Overrides `src_np_image` if provided.
|
|
30
|
+
src_np_image : np.ndarray | None, optional
|
|
31
|
+
Preloaded image array. Used if `src_image_path` is None.
|
|
32
|
+
output_image_path : str | None, optional
|
|
33
|
+
Path to save cropped image.
|
|
21
34
|
|
|
22
|
-
Returns
|
|
23
|
-
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
np.ndarray
|
|
38
|
+
Cropped image.
|
|
24
39
|
|
|
25
|
-
Raises
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
TypeError
|
|
43
|
+
If coordinates are not tuples of two integers.
|
|
44
|
+
ValueError
|
|
45
|
+
If coordinates are invalid or outside image bounds.
|
|
46
|
+
FileNotFoundError
|
|
47
|
+
If `src_image_path` does not exist.
|
|
48
|
+
IOError
|
|
49
|
+
If saving the image fails.
|
|
28
50
|
"""
|
|
29
51
|
# Validate coordinates
|
|
30
52
|
if (
|
|
@@ -33,7 +55,7 @@ def crop_image(start_point, end_point, image_path=None, np_image=None, result_pa
|
|
|
33
55
|
len(start_point) != 2 or len(end_point) != 2 or
|
|
34
56
|
not all(isinstance(c, int) for c in start_point + end_point)
|
|
35
57
|
):
|
|
36
|
-
raise TypeError("
|
|
58
|
+
raise TypeError("'start_point' and 'end_point' must be (x, y) tuples of integers.")
|
|
37
59
|
|
|
38
60
|
x1, y1 = start_point
|
|
39
61
|
x2, y2 = end_point
|
|
@@ -41,11 +63,14 @@ def crop_image(start_point, end_point, image_path=None, np_image=None, result_pa
|
|
|
41
63
|
if x1 < 0 or y1 < 0 or x2 <= x1 or y2 <= y1:
|
|
42
64
|
raise ValueError("Invalid crop coordinates: ensure (x1, y1) is top-left and (x2, y2) is bottom-right.")
|
|
43
65
|
|
|
44
|
-
np_image = IOHandler.load_image(image_path=
|
|
66
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
45
67
|
height, width = np_image.shape[:2]
|
|
46
68
|
|
|
47
69
|
if x2 > width or y2 > height:
|
|
48
70
|
raise ValueError(f"Crop area exceeds image bounds ({width}x{height}).")
|
|
49
71
|
|
|
50
72
|
cropped = np_image[y1:y2, x1:x2]
|
|
51
|
-
|
|
73
|
+
|
|
74
|
+
if output_image_path:
|
|
75
|
+
print(IOHandler.save_image(cropped, output_image_path))
|
|
76
|
+
return cropped
|
|
@@ -1,27 +1,49 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
|
|
3
|
+
import numpy as np
|
|
4
4
|
import cv2
|
|
5
5
|
|
|
6
6
|
# Add parent directory to sys.path for importing custom modules
|
|
7
7
|
parent_dir = Path(__file__).resolve().parent.parent
|
|
8
8
|
sys.path.append(str(parent_dir))
|
|
9
9
|
|
|
10
|
-
from io_handler import IOHandler
|
|
10
|
+
from utils.io_handler import IOHandler
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def convert_to_grayscale(
|
|
13
|
+
def convert_to_grayscale(
|
|
14
|
+
src_image_path: str | None = None,
|
|
15
|
+
src_np_image: np.ndarray | None = None,
|
|
16
|
+
output_image_path: str | None = None
|
|
17
|
+
) -> np.ndarray:
|
|
14
18
|
"""
|
|
15
19
|
Convert a BGR image to single-channel grayscale.
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
src_image_path : str | None, optional
|
|
24
|
+
Path to the input image file.
|
|
25
|
+
src_np_image : np.ndarray | None, optional
|
|
26
|
+
Preloaded BGR image. Used if `src_image_path` is None.
|
|
27
|
+
output_image_path : str | None, optional
|
|
28
|
+
Path to save the grayscale image.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
np.ndarray
|
|
33
|
+
Grayscale image.
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
Raises
|
|
36
|
+
------
|
|
37
|
+
TypeError
|
|
38
|
+
If input types are invalid.
|
|
39
|
+
FileNotFoundError
|
|
40
|
+
If the provided `src_image_path` does not exist.
|
|
41
|
+
IOError
|
|
42
|
+
If saving the image fails.
|
|
24
43
|
"""
|
|
25
|
-
np_image = IOHandler.load_image(image_path=
|
|
44
|
+
np_image = IOHandler.load_image(image_path=src_image_path, np_image=src_np_image)
|
|
26
45
|
grayscale = cv2.cvtColor(np_image, cv2.COLOR_BGR2GRAY)
|
|
27
|
-
|
|
46
|
+
|
|
47
|
+
if output_image_path:
|
|
48
|
+
print(IOHandler.save_image(grayscale, output_image_path))
|
|
49
|
+
return grayscale
|