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.
@@ -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(kernel_size=(5, 5), image_path=None, np_image=None, result_path=None):
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
- Args:
19
- kernel_size (tuple): (width, height) of the blur kernel.
20
- image_path (str, optional): Path to input image.
21
- np_image (np.ndarray, optional): Image array.
22
- result_path (str, optional): Path to save output.
23
-
24
- Returns:
25
- str or np.ndarray: Saved message or blurred image.
26
-
27
- Raises:
28
- TypeError, ValueError: On invalid inputs.
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(blurred, result_path)
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(kernel_size=(5, 5), image_path=None, np_image=None, result_path=None):
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
- Args:
47
- kernel_size (tuple): (width, height), both odd positive integers.
48
- image_path (str, optional): Path to input image.
49
- np_image (np.ndarray, optional): Image array.
50
- result_path (str, optional): Path to save output.
51
-
52
- Returns:
53
- str or np.ndarray: Saved message or blurred image.
54
-
55
- Raises:
56
- TypeError, ValueError: On invalid inputs.
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(blurred, result_path)
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(filter_size=5, image_path=None, np_image=None, result_path=None):
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
- Args:
75
- filter_size (int): Must be an odd integer greater than 1.
76
- image_path (str, optional): Path to input image.
77
- np_image (np.ndarray, optional): Image array.
78
- result_path (str, optional): Path to save output.
79
-
80
- Returns:
81
- str or np.ndarray: Saved message or blurred image.
82
-
83
- Raises:
84
- TypeError, ValueError: On invalid inputs.
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(blurred, result_path)
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
- image_path=None,
101
- np_image=None,
102
- result_path=None,
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
- Args:
108
- filter_size (int): Diameter of pixel neighborhood.
109
- sigma_color (float): Color-space standard deviation.
110
- sigma_space (float): Coordinate-space standard deviation.
111
- image_path (str, optional): Path to input image.
112
- np_image (np.ndarray, optional): Image array.
113
- result_path (str, optional): Path to save output.
114
-
115
- Returns:
116
- str or np.ndarray: Saved message or blurred image.
117
-
118
- Raises:
119
- TypeError, ValueError: On invalid inputs.
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(blurred, result_path)
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
- clipLimit=2.0,
17
- tileGridSize=(8, 8),
18
- image_path=None,
19
- np_image=None,
20
- result_path=None,
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
- Args:
26
- clipLimit (float): Contrast threshold (must be > 0).
27
- tileGridSize (tuple): Grid size for local histogram (e.g., (8, 8)).
28
- image_path (str, optional): Path to input image.
29
- np_image (np.ndarray, optional): Image array.
30
- result_path (str, optional): Path to save result.
31
-
32
- Returns:
33
- str or np.ndarray: Confirmation if saved, else enhanced image.
34
-
35
- Raises:
36
- ValueError, TypeError: On invalid parameter values.
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(clipLimit, (int, float)) or clipLimit <= 0:
39
- raise ValueError("'clipLimit' must be a positive number.")
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(tileGridSize, tuple)
43
- or len(tileGridSize) != 2
44
- or not all(isinstance(i, int) and i > 0 for i in tileGridSize)
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("'tileGridSize' must be a tuple of two positive integers.")
61
+ raise TypeError("'tile_grid_size' must be a tuple of two positive integers.")
47
62
 
48
- np_image = convert_to_grayscale(np_image=IOHandler.load_image(image_path=image_path, np_image=np_image))
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=clipLimit, tileGridSize=tileGridSize)
67
+ clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_grid_size)
51
68
  enhanced = clahe.apply(np_image)
52
69
 
53
- return IOHandler.save_image(enhanced, result_path)
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(image_path=None, np_image=None, result_path=None):
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
- Args:
61
- image_path (str, optional): Path to input image.
62
- np_image (np.ndarray, optional): Image array.
63
- result_path (str, optional): Path to save result.
64
-
65
- Returns:
66
- str or np.ndarray: Confirmation if saved, else enhanced image.
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(np_image=IOHandler.load_image(image_path=image_path, np_image=np_image))
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
- return IOHandler.save_image(enhanced, result_path)
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
- image_path=None,
77
- np_image=None,
78
- result_path=None,
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 contrast stretching (alpha × pixel + beta).
82
-
83
- Args:
84
- alpha (float): Contrast factor (>= 0).
85
- beta (int): Brightness offset (0–255).
86
- image_path (str, optional): Path to input image.
87
- np_image (np.ndarray, optional): Image array.
88
- result_path (str, optional): Path to save result.
89
-
90
- Returns:
91
- str or np.ndarray: Confirmation if saved, else enhanced image.
92
-
93
- Raises:
94
- ValueError: If parameters are out of range.
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(np_image=IOHandler.load_image(image_path=image_path, np_image=np_image))
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
- return IOHandler.save_image(enhanced, result_path)
151
+ if output_image_path:
152
+ print(IOHandler.save_image(enhanced, output_image_path))
153
+ return enhanced
@@ -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(start_point, end_point, image_path=None, np_image=None, result_path=None):
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
- Args:
16
- start_point (tuple): (x1, y1) top-left corner.
17
- end_point (tuple): (x2, y2) bottom-right corner.
18
- image_path (str, optional): Path to input image. Overrides `np_image` if provided.
19
- np_image (np.ndarray, optional): Image array. Used if `image_path` is None.
20
- result_path (str, optional): Path to save cropped image.
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
- str or np.ndarray: Save message if saved, else cropped image array.
35
+ Returns
36
+ -------
37
+ np.ndarray
38
+ Cropped image.
24
39
 
25
- Raises:
26
- TypeError: If inputs are not proper tuples of integers.
27
- ValueError: If coordinates are invalid or out of image bounds.
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("Both 'start_point' and 'end_point' must be (x, y) tuples of integers.")
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(cropped, result_path)
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(image_path=None, np_image=None, result_path=None):
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
- Args:
18
- image_path (str, optional): Path to input image file.
19
- np_image (np.ndarray, optional): Image array (used if image_path is None).
20
- result_path (str, optional): Path to save grayscale image.
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
- Returns:
23
- str or np.ndarray: Confirmation message if saved, else grayscale image.
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=image_path, np_image=np_image)
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
- return IOHandler.save_image(grayscale, result_path)
46
+
47
+ if output_image_path:
48
+ print(IOHandler.save_image(grayscale, output_image_path))
49
+ return grayscale