stouputils 1.14.0__py3-none-any.whl → 1.14.2__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.
- stouputils/__init__.pyi +15 -0
- stouputils/_deprecated.pyi +12 -0
- stouputils/all_doctests.pyi +46 -0
- stouputils/applications/__init__.pyi +2 -0
- stouputils/applications/automatic_docs.py +3 -0
- stouputils/applications/automatic_docs.pyi +106 -0
- stouputils/applications/upscaler/__init__.pyi +3 -0
- stouputils/applications/upscaler/config.pyi +18 -0
- stouputils/applications/upscaler/image.pyi +109 -0
- stouputils/applications/upscaler/video.pyi +60 -0
- stouputils/archive.pyi +67 -0
- stouputils/backup.pyi +109 -0
- stouputils/collections.pyi +86 -0
- stouputils/continuous_delivery/__init__.pyi +5 -0
- stouputils/continuous_delivery/cd_utils.pyi +129 -0
- stouputils/continuous_delivery/github.pyi +162 -0
- stouputils/continuous_delivery/pypi.pyi +52 -0
- stouputils/continuous_delivery/pyproject.pyi +67 -0
- stouputils/continuous_delivery/stubs.pyi +39 -0
- stouputils/ctx.pyi +211 -0
- stouputils/data_science/config/get.py +51 -51
- stouputils/data_science/data_processing/image/__init__.py +66 -66
- stouputils/data_science/data_processing/image/auto_contrast.py +79 -79
- stouputils/data_science/data_processing/image/axis_flip.py +58 -58
- stouputils/data_science/data_processing/image/bias_field_correction.py +74 -74
- stouputils/data_science/data_processing/image/binary_threshold.py +73 -73
- stouputils/data_science/data_processing/image/blur.py +59 -59
- stouputils/data_science/data_processing/image/brightness.py +54 -54
- stouputils/data_science/data_processing/image/canny.py +110 -110
- stouputils/data_science/data_processing/image/clahe.py +92 -92
- stouputils/data_science/data_processing/image/common.py +30 -30
- stouputils/data_science/data_processing/image/contrast.py +53 -53
- stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -74
- stouputils/data_science/data_processing/image/denoise.py +378 -378
- stouputils/data_science/data_processing/image/histogram_equalization.py +123 -123
- stouputils/data_science/data_processing/image/invert.py +64 -64
- stouputils/data_science/data_processing/image/laplacian.py +60 -60
- stouputils/data_science/data_processing/image/median_blur.py +52 -52
- stouputils/data_science/data_processing/image/noise.py +59 -59
- stouputils/data_science/data_processing/image/normalize.py +65 -65
- stouputils/data_science/data_processing/image/random_erase.py +66 -66
- stouputils/data_science/data_processing/image/resize.py +69 -69
- stouputils/data_science/data_processing/image/rotation.py +80 -80
- stouputils/data_science/data_processing/image/salt_pepper.py +68 -68
- stouputils/data_science/data_processing/image/sharpening.py +55 -55
- stouputils/data_science/data_processing/image/shearing.py +64 -64
- stouputils/data_science/data_processing/image/threshold.py +64 -64
- stouputils/data_science/data_processing/image/translation.py +71 -71
- stouputils/data_science/data_processing/image/zoom.py +83 -83
- stouputils/data_science/data_processing/image_augmentation.py +118 -118
- stouputils/data_science/data_processing/image_preprocess.py +183 -183
- stouputils/data_science/data_processing/prosthesis_detection.py +359 -359
- stouputils/data_science/data_processing/technique.py +481 -481
- stouputils/data_science/dataset/__init__.py +45 -45
- stouputils/data_science/dataset/dataset.py +292 -292
- stouputils/data_science/dataset/dataset_loader.py +135 -135
- stouputils/data_science/dataset/grouping_strategy.py +296 -296
- stouputils/data_science/dataset/image_loader.py +100 -100
- stouputils/data_science/dataset/xy_tuple.py +696 -696
- stouputils/data_science/metric_dictionnary.py +106 -106
- stouputils/data_science/mlflow_utils.py +206 -206
- stouputils/data_science/models/abstract_model.py +149 -149
- stouputils/data_science/models/all.py +85 -85
- stouputils/data_science/models/keras/all.py +38 -38
- stouputils/data_science/models/keras/convnext.py +62 -62
- stouputils/data_science/models/keras/densenet.py +50 -50
- stouputils/data_science/models/keras/efficientnet.py +60 -60
- stouputils/data_science/models/keras/mobilenet.py +56 -56
- stouputils/data_science/models/keras/resnet.py +52 -52
- stouputils/data_science/models/keras/squeezenet.py +233 -233
- stouputils/data_science/models/keras/vgg.py +42 -42
- stouputils/data_science/models/keras/xception.py +38 -38
- stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -20
- stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -219
- stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -148
- stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -31
- stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -249
- stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -66
- stouputils/data_science/models/keras_utils/losses/__init__.py +12 -12
- stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -56
- stouputils/data_science/models/keras_utils/visualizations.py +416 -416
- stouputils/data_science/models/sandbox.py +116 -116
- stouputils/data_science/range_tuple.py +234 -234
- stouputils/data_science/utils.py +285 -285
- stouputils/decorators.pyi +242 -0
- stouputils/image.pyi +172 -0
- stouputils/installer/__init__.py +18 -18
- stouputils/installer/__init__.pyi +5 -0
- stouputils/installer/common.pyi +39 -0
- stouputils/installer/downloader.pyi +24 -0
- stouputils/installer/linux.py +144 -144
- stouputils/installer/linux.pyi +39 -0
- stouputils/installer/main.py +223 -223
- stouputils/installer/main.pyi +57 -0
- stouputils/installer/windows.py +136 -136
- stouputils/installer/windows.pyi +31 -0
- stouputils/io.pyi +213 -0
- stouputils/parallel.py +12 -10
- stouputils/parallel.pyi +211 -0
- stouputils/print.pyi +136 -0
- stouputils/py.typed +1 -1
- stouputils/stouputils/parallel.pyi +4 -4
- stouputils/version_pkg.pyi +15 -0
- {stouputils-1.14.0.dist-info → stouputils-1.14.2.dist-info}/METADATA +1 -1
- stouputils-1.14.2.dist-info/RECORD +171 -0
- stouputils-1.14.0.dist-info/RECORD +0 -140
- {stouputils-1.14.0.dist-info → stouputils-1.14.2.dist-info}/WHEEL +0 -0
- {stouputils-1.14.0.dist-info → stouputils-1.14.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
|
|
2
|
-
# pyright: reportUnusedImport=false
|
|
3
|
-
# ruff: noqa: F401
|
|
4
|
-
|
|
5
|
-
# Imports
|
|
6
|
-
from typing import Literal
|
|
7
|
-
|
|
8
|
-
from .common import Any, NDArray, check_image, cv2, np
|
|
9
|
-
|
|
10
|
-
# Constants
|
|
11
|
-
VALID_SPACES: list[str] = ["lab", "ycbcr", "hsv"]
|
|
12
|
-
|
|
13
|
-
# Color space conversion constants
|
|
14
|
-
COLOR_SPACE_CONSTANTS: dict[str, tuple[int, int, int]] = {
|
|
15
|
-
"lab": (cv2.COLOR_BGR2LAB, cv2.COLOR_LAB2BGR, 0), # L channel index is 0
|
|
16
|
-
"ycbcr": (cv2.COLOR_BGR2YCrCb, cv2.COLOR_YCrCb2BGR, 0), # Y channel index is 0
|
|
17
|
-
"hsv": (cv2.COLOR_BGR2HSV, cv2.COLOR_HSV2BGR, 2), # V channel index is 2
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# Functions
|
|
22
|
-
def histogram_equalization_image(
|
|
23
|
-
image: NDArray[Any],
|
|
24
|
-
color_space: Literal["lab", "ycbcr", "hsv"] = "lab",
|
|
25
|
-
ignore_dtype: bool = False,
|
|
26
|
-
) -> NDArray[Any]:
|
|
27
|
-
""" Apply standard histogram equalization to an image.
|
|
28
|
-
|
|
29
|
-
Histogram equalization improves the contrast in images by stretching
|
|
30
|
-
the intensity range to utilize the full range of intensity values.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
image (NDArray[Any]): Image to apply histogram equalization to
|
|
34
|
-
color_space (str): Color space to use for equalization ("lab", "ycbcr", or "hsv")
|
|
35
|
-
"lab": CIELab color space (perceptually uniform, best visual fidelity)
|
|
36
|
-
"ycbcr": YCbCr color space (fast, good balance)
|
|
37
|
-
"hsv": HSV color space (intuitive, may cause color shifts)
|
|
38
|
-
ignore_dtype (bool): Ignore the dtype check
|
|
39
|
-
Returns:
|
|
40
|
-
NDArray[Any]: Image with histogram equalization applied
|
|
41
|
-
|
|
42
|
-
>>> ## Basic tests
|
|
43
|
-
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
44
|
-
>>> histogram_equalization_image(image.astype(np.uint8)).tolist()
|
|
45
|
-
[[0, 32, 64], [96, 128, 159], [191, 223, 255]]
|
|
46
|
-
|
|
47
|
-
>>> img = np.full((5,5), 128, dtype=np.uint8)
|
|
48
|
-
>>> img[1:3, 1:3] = 200 # Create a bright region
|
|
49
|
-
>>> histogram_equalization_image(img).tolist()
|
|
50
|
-
[[0, 0, 0, 0, 0], [0, 255, 255, 0, 0], [0, 255, 255, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
|
|
51
|
-
|
|
52
|
-
>>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
|
|
53
|
-
>>> rgb[1, 1, :] = 50 # Create a dark region
|
|
54
|
-
>>> equalized_rgb = histogram_equalization_image(rgb)
|
|
55
|
-
>>> bool(np.std(equalized_rgb) > np.std(rgb)) # Should enhance contrast
|
|
56
|
-
True
|
|
57
|
-
>>> equalized_rgb.tolist()
|
|
58
|
-
[[[255, 255, 255], [255, 255, 255], [255, 255, 255]], [[255, 255, 255], [0, 0, 0], [255, 255, 255]], [[255, 255, 255], [255, 255, 255], [255, 255, 255]]]
|
|
59
|
-
|
|
60
|
-
>>> ## Test each color space
|
|
61
|
-
>>> test_img = np.zeros((20, 20, 3), dtype=np.uint8)
|
|
62
|
-
>>> test_img[5:15, 5:15] = 200 # Add contrast region
|
|
63
|
-
|
|
64
|
-
>>> # Test LAB color space
|
|
65
|
-
>>> lab_result = histogram_equalization_image(test_img, color_space="lab")
|
|
66
|
-
>>> isinstance(lab_result, np.ndarray) and lab_result.shape == test_img.shape
|
|
67
|
-
True
|
|
68
|
-
>>> bool(np.std(lab_result) > np.std(test_img)) # Verify contrast enhancement
|
|
69
|
-
True
|
|
70
|
-
|
|
71
|
-
>>> # Test YCbCr color space
|
|
72
|
-
>>> ycbcr_result = histogram_equalization_image(test_img, color_space="ycbcr")
|
|
73
|
-
>>> isinstance(ycbcr_result, np.ndarray) and ycbcr_result.shape == test_img.shape
|
|
74
|
-
True
|
|
75
|
-
>>> bool(np.std(ycbcr_result) > np.std(test_img)) # Verify contrast enhancement
|
|
76
|
-
True
|
|
77
|
-
|
|
78
|
-
>>> # Test HSV color space
|
|
79
|
-
>>> hsv_result = histogram_equalization_image(test_img, color_space="hsv")
|
|
80
|
-
>>> isinstance(hsv_result, np.ndarray) and hsv_result.shape == test_img.shape
|
|
81
|
-
True
|
|
82
|
-
>>> bool(np.std(hsv_result) > np.std(test_img)) # Verify contrast enhancement
|
|
83
|
-
True
|
|
84
|
-
|
|
85
|
-
>>> ## Test invalid inputs
|
|
86
|
-
>>> histogram_equalization_image("not an image")
|
|
87
|
-
Traceback (most recent call last):
|
|
88
|
-
...
|
|
89
|
-
AssertionError: Image must be a numpy array
|
|
90
|
-
|
|
91
|
-
>>> histogram_equalization_image(rgb, "invalid_space")
|
|
92
|
-
Traceback (most recent call last):
|
|
93
|
-
...
|
|
94
|
-
AssertionError: color_space must be one of: lab, ycbcr, hsv
|
|
95
|
-
""" # noqa: E501
|
|
96
|
-
# Check input data
|
|
97
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
98
|
-
lowered_color_space = color_space.lower()
|
|
99
|
-
assert lowered_color_space in VALID_SPACES, f"color_space must be one of: {', '.join(VALID_SPACES)}"
|
|
100
|
-
|
|
101
|
-
# Handle different image types
|
|
102
|
-
if len(image.shape) == 2:
|
|
103
|
-
# Grayscale image - just apply histogram equalization directly
|
|
104
|
-
return cv2.equalizeHist(image)
|
|
105
|
-
else:
|
|
106
|
-
# Color image - apply equalization based on selected color space
|
|
107
|
-
convert_to, convert_from, channel_idx = COLOR_SPACE_CONSTANTS[lowered_color_space]
|
|
108
|
-
|
|
109
|
-
# Convert to target color space
|
|
110
|
-
converted: NDArray[Any] = cv2.cvtColor(image, convert_to)
|
|
111
|
-
|
|
112
|
-
# Split channels
|
|
113
|
-
channels: list[NDArray[Any]] = list(cv2.split(converted))
|
|
114
|
-
|
|
115
|
-
# Apply histogram equalization to the appropriate channel
|
|
116
|
-
channels[channel_idx] = cv2.equalizeHist(channels[channel_idx])
|
|
117
|
-
|
|
118
|
-
# Merge channels
|
|
119
|
-
result: NDArray[Any] = cv2.merge(channels)
|
|
120
|
-
|
|
121
|
-
# Convert back to BGR
|
|
122
|
-
return cv2.cvtColor(result, convert_from)
|
|
123
|
-
|
|
1
|
+
|
|
2
|
+
# pyright: reportUnusedImport=false
|
|
3
|
+
# ruff: noqa: F401
|
|
4
|
+
|
|
5
|
+
# Imports
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
from .common import Any, NDArray, check_image, cv2, np
|
|
9
|
+
|
|
10
|
+
# Constants
|
|
11
|
+
VALID_SPACES: list[str] = ["lab", "ycbcr", "hsv"]
|
|
12
|
+
|
|
13
|
+
# Color space conversion constants
|
|
14
|
+
COLOR_SPACE_CONSTANTS: dict[str, tuple[int, int, int]] = {
|
|
15
|
+
"lab": (cv2.COLOR_BGR2LAB, cv2.COLOR_LAB2BGR, 0), # L channel index is 0
|
|
16
|
+
"ycbcr": (cv2.COLOR_BGR2YCrCb, cv2.COLOR_YCrCb2BGR, 0), # Y channel index is 0
|
|
17
|
+
"hsv": (cv2.COLOR_BGR2HSV, cv2.COLOR_HSV2BGR, 2), # V channel index is 2
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Functions
|
|
22
|
+
def histogram_equalization_image(
|
|
23
|
+
image: NDArray[Any],
|
|
24
|
+
color_space: Literal["lab", "ycbcr", "hsv"] = "lab",
|
|
25
|
+
ignore_dtype: bool = False,
|
|
26
|
+
) -> NDArray[Any]:
|
|
27
|
+
""" Apply standard histogram equalization to an image.
|
|
28
|
+
|
|
29
|
+
Histogram equalization improves the contrast in images by stretching
|
|
30
|
+
the intensity range to utilize the full range of intensity values.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
image (NDArray[Any]): Image to apply histogram equalization to
|
|
34
|
+
color_space (str): Color space to use for equalization ("lab", "ycbcr", or "hsv")
|
|
35
|
+
"lab": CIELab color space (perceptually uniform, best visual fidelity)
|
|
36
|
+
"ycbcr": YCbCr color space (fast, good balance)
|
|
37
|
+
"hsv": HSV color space (intuitive, may cause color shifts)
|
|
38
|
+
ignore_dtype (bool): Ignore the dtype check
|
|
39
|
+
Returns:
|
|
40
|
+
NDArray[Any]: Image with histogram equalization applied
|
|
41
|
+
|
|
42
|
+
>>> ## Basic tests
|
|
43
|
+
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
44
|
+
>>> histogram_equalization_image(image.astype(np.uint8)).tolist()
|
|
45
|
+
[[0, 32, 64], [96, 128, 159], [191, 223, 255]]
|
|
46
|
+
|
|
47
|
+
>>> img = np.full((5,5), 128, dtype=np.uint8)
|
|
48
|
+
>>> img[1:3, 1:3] = 200 # Create a bright region
|
|
49
|
+
>>> histogram_equalization_image(img).tolist()
|
|
50
|
+
[[0, 0, 0, 0, 0], [0, 255, 255, 0, 0], [0, 255, 255, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
|
|
51
|
+
|
|
52
|
+
>>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
|
|
53
|
+
>>> rgb[1, 1, :] = 50 # Create a dark region
|
|
54
|
+
>>> equalized_rgb = histogram_equalization_image(rgb)
|
|
55
|
+
>>> bool(np.std(equalized_rgb) > np.std(rgb)) # Should enhance contrast
|
|
56
|
+
True
|
|
57
|
+
>>> equalized_rgb.tolist()
|
|
58
|
+
[[[255, 255, 255], [255, 255, 255], [255, 255, 255]], [[255, 255, 255], [0, 0, 0], [255, 255, 255]], [[255, 255, 255], [255, 255, 255], [255, 255, 255]]]
|
|
59
|
+
|
|
60
|
+
>>> ## Test each color space
|
|
61
|
+
>>> test_img = np.zeros((20, 20, 3), dtype=np.uint8)
|
|
62
|
+
>>> test_img[5:15, 5:15] = 200 # Add contrast region
|
|
63
|
+
|
|
64
|
+
>>> # Test LAB color space
|
|
65
|
+
>>> lab_result = histogram_equalization_image(test_img, color_space="lab")
|
|
66
|
+
>>> isinstance(lab_result, np.ndarray) and lab_result.shape == test_img.shape
|
|
67
|
+
True
|
|
68
|
+
>>> bool(np.std(lab_result) > np.std(test_img)) # Verify contrast enhancement
|
|
69
|
+
True
|
|
70
|
+
|
|
71
|
+
>>> # Test YCbCr color space
|
|
72
|
+
>>> ycbcr_result = histogram_equalization_image(test_img, color_space="ycbcr")
|
|
73
|
+
>>> isinstance(ycbcr_result, np.ndarray) and ycbcr_result.shape == test_img.shape
|
|
74
|
+
True
|
|
75
|
+
>>> bool(np.std(ycbcr_result) > np.std(test_img)) # Verify contrast enhancement
|
|
76
|
+
True
|
|
77
|
+
|
|
78
|
+
>>> # Test HSV color space
|
|
79
|
+
>>> hsv_result = histogram_equalization_image(test_img, color_space="hsv")
|
|
80
|
+
>>> isinstance(hsv_result, np.ndarray) and hsv_result.shape == test_img.shape
|
|
81
|
+
True
|
|
82
|
+
>>> bool(np.std(hsv_result) > np.std(test_img)) # Verify contrast enhancement
|
|
83
|
+
True
|
|
84
|
+
|
|
85
|
+
>>> ## Test invalid inputs
|
|
86
|
+
>>> histogram_equalization_image("not an image")
|
|
87
|
+
Traceback (most recent call last):
|
|
88
|
+
...
|
|
89
|
+
AssertionError: Image must be a numpy array
|
|
90
|
+
|
|
91
|
+
>>> histogram_equalization_image(rgb, "invalid_space")
|
|
92
|
+
Traceback (most recent call last):
|
|
93
|
+
...
|
|
94
|
+
AssertionError: color_space must be one of: lab, ycbcr, hsv
|
|
95
|
+
""" # noqa: E501
|
|
96
|
+
# Check input data
|
|
97
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
98
|
+
lowered_color_space = color_space.lower()
|
|
99
|
+
assert lowered_color_space in VALID_SPACES, f"color_space must be one of: {', '.join(VALID_SPACES)}"
|
|
100
|
+
|
|
101
|
+
# Handle different image types
|
|
102
|
+
if len(image.shape) == 2:
|
|
103
|
+
# Grayscale image - just apply histogram equalization directly
|
|
104
|
+
return cv2.equalizeHist(image)
|
|
105
|
+
else:
|
|
106
|
+
# Color image - apply equalization based on selected color space
|
|
107
|
+
convert_to, convert_from, channel_idx = COLOR_SPACE_CONSTANTS[lowered_color_space]
|
|
108
|
+
|
|
109
|
+
# Convert to target color space
|
|
110
|
+
converted: NDArray[Any] = cv2.cvtColor(image, convert_to)
|
|
111
|
+
|
|
112
|
+
# Split channels
|
|
113
|
+
channels: list[NDArray[Any]] = list(cv2.split(converted))
|
|
114
|
+
|
|
115
|
+
# Apply histogram equalization to the appropriate channel
|
|
116
|
+
channels[channel_idx] = cv2.equalizeHist(channels[channel_idx])
|
|
117
|
+
|
|
118
|
+
# Merge channels
|
|
119
|
+
result: NDArray[Any] = cv2.merge(channels)
|
|
120
|
+
|
|
121
|
+
# Convert back to BGR
|
|
122
|
+
return cv2.cvtColor(result, convert_from)
|
|
123
|
+
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
# Imports
|
|
3
|
-
from .common import Any, NDArray, check_image, np
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# Function
|
|
7
|
-
def invert_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
8
|
-
""" Invert the colors of an image.
|
|
9
|
-
|
|
10
|
-
This function inverts the colors of the input image by subtracting each pixel value
|
|
11
|
-
from the maximum possible value based on the image type.
|
|
12
|
-
|
|
13
|
-
Args:
|
|
14
|
-
image (NDArray[Any]): Input image as a NumPy array.
|
|
15
|
-
ignore_dtype (bool): Ignore the dtype check.
|
|
16
|
-
Returns:
|
|
17
|
-
NDArray[Any]: Image with inverted colors.
|
|
18
|
-
|
|
19
|
-
>>> ## Basic tests
|
|
20
|
-
>>> image = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]], dtype=np.uint8)
|
|
21
|
-
>>> inverted = invert_image(image)
|
|
22
|
-
>>> inverted.tolist()
|
|
23
|
-
[[245, 235, 225], [215, 205, 195], [185, 175, 165]]
|
|
24
|
-
|
|
25
|
-
>>> # Test with floating point image
|
|
26
|
-
>>> float_img = np.array([[0.1, 0.2], [0.3, 0.4]], dtype=np.float32)
|
|
27
|
-
>>> [round(float(x), 1) for x in invert_image(float_img).flatten()]
|
|
28
|
-
[0.9, 0.8, 0.7, 0.6]
|
|
29
|
-
|
|
30
|
-
>>> # Test with RGB image
|
|
31
|
-
>>> rgb = np.zeros((2, 2, 3), dtype=np.uint8)
|
|
32
|
-
>>> rgb[0, 0] = [255, 0, 0] # Red pixel
|
|
33
|
-
>>> inverted_rgb = invert_image(rgb)
|
|
34
|
-
>>> inverted_rgb[0, 0].tolist()
|
|
35
|
-
[0, 255, 255]
|
|
36
|
-
|
|
37
|
-
>>> ## Test invalid inputs
|
|
38
|
-
>>> invert_image("not an image")
|
|
39
|
-
Traceback (most recent call last):
|
|
40
|
-
...
|
|
41
|
-
AssertionError: Image must be a numpy array
|
|
42
|
-
"""
|
|
43
|
-
# Check input data
|
|
44
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
45
|
-
|
|
46
|
-
# Get the maximum value based on the image's data type
|
|
47
|
-
if image.dtype == np.uint8:
|
|
48
|
-
max_value = 255
|
|
49
|
-
elif image.dtype == np.uint16:
|
|
50
|
-
max_value = 65535
|
|
51
|
-
elif image.dtype == np.float32 or image.dtype == np.float64:
|
|
52
|
-
# For float images, we assume range [0, 1]
|
|
53
|
-
max_value = 1.0
|
|
54
|
-
else:
|
|
55
|
-
# Default case, assuming 8-bit
|
|
56
|
-
max_value = 255
|
|
57
|
-
image = image.astype(np.uint8)
|
|
58
|
-
|
|
59
|
-
# Invert the image
|
|
60
|
-
inverted = max_value - image
|
|
61
|
-
|
|
62
|
-
# Ensure we return the same dtype as the input
|
|
63
|
-
return inverted.astype(image.dtype)
|
|
64
|
-
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
from .common import Any, NDArray, check_image, np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Function
|
|
7
|
+
def invert_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
8
|
+
""" Invert the colors of an image.
|
|
9
|
+
|
|
10
|
+
This function inverts the colors of the input image by subtracting each pixel value
|
|
11
|
+
from the maximum possible value based on the image type.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
image (NDArray[Any]): Input image as a NumPy array.
|
|
15
|
+
ignore_dtype (bool): Ignore the dtype check.
|
|
16
|
+
Returns:
|
|
17
|
+
NDArray[Any]: Image with inverted colors.
|
|
18
|
+
|
|
19
|
+
>>> ## Basic tests
|
|
20
|
+
>>> image = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]], dtype=np.uint8)
|
|
21
|
+
>>> inverted = invert_image(image)
|
|
22
|
+
>>> inverted.tolist()
|
|
23
|
+
[[245, 235, 225], [215, 205, 195], [185, 175, 165]]
|
|
24
|
+
|
|
25
|
+
>>> # Test with floating point image
|
|
26
|
+
>>> float_img = np.array([[0.1, 0.2], [0.3, 0.4]], dtype=np.float32)
|
|
27
|
+
>>> [round(float(x), 1) for x in invert_image(float_img).flatten()]
|
|
28
|
+
[0.9, 0.8, 0.7, 0.6]
|
|
29
|
+
|
|
30
|
+
>>> # Test with RGB image
|
|
31
|
+
>>> rgb = np.zeros((2, 2, 3), dtype=np.uint8)
|
|
32
|
+
>>> rgb[0, 0] = [255, 0, 0] # Red pixel
|
|
33
|
+
>>> inverted_rgb = invert_image(rgb)
|
|
34
|
+
>>> inverted_rgb[0, 0].tolist()
|
|
35
|
+
[0, 255, 255]
|
|
36
|
+
|
|
37
|
+
>>> ## Test invalid inputs
|
|
38
|
+
>>> invert_image("not an image")
|
|
39
|
+
Traceback (most recent call last):
|
|
40
|
+
...
|
|
41
|
+
AssertionError: Image must be a numpy array
|
|
42
|
+
"""
|
|
43
|
+
# Check input data
|
|
44
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
45
|
+
|
|
46
|
+
# Get the maximum value based on the image's data type
|
|
47
|
+
if image.dtype == np.uint8:
|
|
48
|
+
max_value = 255
|
|
49
|
+
elif image.dtype == np.uint16:
|
|
50
|
+
max_value = 65535
|
|
51
|
+
elif image.dtype == np.float32 or image.dtype == np.float64:
|
|
52
|
+
# For float images, we assume range [0, 1]
|
|
53
|
+
max_value = 1.0
|
|
54
|
+
else:
|
|
55
|
+
# Default case, assuming 8-bit
|
|
56
|
+
max_value = 255
|
|
57
|
+
image = image.astype(np.uint8)
|
|
58
|
+
|
|
59
|
+
# Invert the image
|
|
60
|
+
inverted = max_value - image
|
|
61
|
+
|
|
62
|
+
# Ensure we return the same dtype as the input
|
|
63
|
+
return inverted.astype(image.dtype)
|
|
64
|
+
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
# pyright: reportUnknownMemberType=false
|
|
3
|
-
# pyright: reportUnknownVariableType=false
|
|
4
|
-
# pyright: reportUnknownArgumentType=false
|
|
5
|
-
# pyright: reportAttributeAccessIssue=false
|
|
6
|
-
# pyright: reportArgumentType=false
|
|
7
|
-
# pyright: reportCallIssue=false
|
|
8
|
-
|
|
9
|
-
# Imports
|
|
10
|
-
from .common import Any, NDArray, check_image, cv2, np
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Functions
|
|
14
|
-
def laplacian_image(image: NDArray[Any], kernel_size: int = 3, ignore_dtype: bool = False) -> NDArray[Any]:
|
|
15
|
-
""" Apply Laplacian edge detection to an image.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
image (NDArray[Any]): Image to apply Laplacian edge detection
|
|
19
|
-
kernel_size (int): Size of the kernel (must be odd)
|
|
20
|
-
ignore_dtype (bool): Ignore the dtype check
|
|
21
|
-
Returns:
|
|
22
|
-
NDArray[Any]: Image with Laplacian edge detection applied
|
|
23
|
-
|
|
24
|
-
>>> ## Basic tests
|
|
25
|
-
>>> image = np.array([[100, 150, 200], [50, 125, 175], [25, 75, 225]])
|
|
26
|
-
>>> edges = laplacian_image(image.astype(np.uint8))
|
|
27
|
-
>>> edges.shape == image.shape[:2] # Laplacian returns single channel
|
|
28
|
-
True
|
|
29
|
-
|
|
30
|
-
>>> rgb = np.random.randint(0, 256, (3,3,3), dtype=np.uint8)
|
|
31
|
-
>>> edges_rgb = laplacian_image(rgb)
|
|
32
|
-
>>> edges_rgb.shape == rgb.shape[:2] # Laplacian returns single channel
|
|
33
|
-
True
|
|
34
|
-
|
|
35
|
-
>>> ## Test invalid inputs
|
|
36
|
-
>>> laplacian_image("not an image")
|
|
37
|
-
Traceback (most recent call last):
|
|
38
|
-
...
|
|
39
|
-
AssertionError: Image must be a numpy array
|
|
40
|
-
|
|
41
|
-
>>> laplacian_image(image.astype(np.uint8), kernel_size=2)
|
|
42
|
-
Traceback (most recent call last):
|
|
43
|
-
...
|
|
44
|
-
AssertionError: kernel_size must be odd, got 2
|
|
45
|
-
"""
|
|
46
|
-
# Check input data
|
|
47
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
48
|
-
assert kernel_size % 2 == 1, f"kernel_size must be odd, got {kernel_size}"
|
|
49
|
-
|
|
50
|
-
# Convert to grayscale if needed
|
|
51
|
-
if len(image.shape) > 2:
|
|
52
|
-
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
53
|
-
|
|
54
|
-
# Apply Laplacian edge detection
|
|
55
|
-
laplacian: NDArray[Any] = cv2.Laplacian(image, cv2.CV_64F, ksize=kernel_size)
|
|
56
|
-
|
|
57
|
-
# Convert back to uint8 and normalize to 0-255 range
|
|
58
|
-
normalized: NDArray[Any] = cv2.normalize(laplacian, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
|
|
59
|
-
return normalized.astype(np.uint8)
|
|
60
|
-
|
|
1
|
+
|
|
2
|
+
# pyright: reportUnknownMemberType=false
|
|
3
|
+
# pyright: reportUnknownVariableType=false
|
|
4
|
+
# pyright: reportUnknownArgumentType=false
|
|
5
|
+
# pyright: reportAttributeAccessIssue=false
|
|
6
|
+
# pyright: reportArgumentType=false
|
|
7
|
+
# pyright: reportCallIssue=false
|
|
8
|
+
|
|
9
|
+
# Imports
|
|
10
|
+
from .common import Any, NDArray, check_image, cv2, np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Functions
|
|
14
|
+
def laplacian_image(image: NDArray[Any], kernel_size: int = 3, ignore_dtype: bool = False) -> NDArray[Any]:
|
|
15
|
+
""" Apply Laplacian edge detection to an image.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
image (NDArray[Any]): Image to apply Laplacian edge detection
|
|
19
|
+
kernel_size (int): Size of the kernel (must be odd)
|
|
20
|
+
ignore_dtype (bool): Ignore the dtype check
|
|
21
|
+
Returns:
|
|
22
|
+
NDArray[Any]: Image with Laplacian edge detection applied
|
|
23
|
+
|
|
24
|
+
>>> ## Basic tests
|
|
25
|
+
>>> image = np.array([[100, 150, 200], [50, 125, 175], [25, 75, 225]])
|
|
26
|
+
>>> edges = laplacian_image(image.astype(np.uint8))
|
|
27
|
+
>>> edges.shape == image.shape[:2] # Laplacian returns single channel
|
|
28
|
+
True
|
|
29
|
+
|
|
30
|
+
>>> rgb = np.random.randint(0, 256, (3,3,3), dtype=np.uint8)
|
|
31
|
+
>>> edges_rgb = laplacian_image(rgb)
|
|
32
|
+
>>> edges_rgb.shape == rgb.shape[:2] # Laplacian returns single channel
|
|
33
|
+
True
|
|
34
|
+
|
|
35
|
+
>>> ## Test invalid inputs
|
|
36
|
+
>>> laplacian_image("not an image")
|
|
37
|
+
Traceback (most recent call last):
|
|
38
|
+
...
|
|
39
|
+
AssertionError: Image must be a numpy array
|
|
40
|
+
|
|
41
|
+
>>> laplacian_image(image.astype(np.uint8), kernel_size=2)
|
|
42
|
+
Traceback (most recent call last):
|
|
43
|
+
...
|
|
44
|
+
AssertionError: kernel_size must be odd, got 2
|
|
45
|
+
"""
|
|
46
|
+
# Check input data
|
|
47
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
48
|
+
assert kernel_size % 2 == 1, f"kernel_size must be odd, got {kernel_size}"
|
|
49
|
+
|
|
50
|
+
# Convert to grayscale if needed
|
|
51
|
+
if len(image.shape) > 2:
|
|
52
|
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
53
|
+
|
|
54
|
+
# Apply Laplacian edge detection
|
|
55
|
+
laplacian: NDArray[Any] = cv2.Laplacian(image, cv2.CV_64F, ksize=kernel_size)
|
|
56
|
+
|
|
57
|
+
# Convert back to uint8 and normalize to 0-255 range
|
|
58
|
+
normalized: NDArray[Any] = cv2.normalize(laplacian, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
|
|
59
|
+
return normalized.astype(np.uint8)
|
|
60
|
+
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
# pyright: reportUnusedImport=false
|
|
3
|
-
# ruff: noqa: F401
|
|
4
|
-
|
|
5
|
-
# Imports
|
|
6
|
-
from .common import Any, NDArray, check_image, cv2, np
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# Functions
|
|
10
|
-
def median_blur_image(image: NDArray[Any], kernel_size: int = 7, iterations: int = 1) -> NDArray[Any]:
|
|
11
|
-
""" Apply median blur to an image.
|
|
12
|
-
|
|
13
|
-
Args:
|
|
14
|
-
image (NDArray[Any]): Image to apply median blur
|
|
15
|
-
kernel_size (int): Kernel size for the median blur
|
|
16
|
-
iterations (int): Number of iterations for the median blur
|
|
17
|
-
Returns:
|
|
18
|
-
NDArray[Any]: Image with median blur applied
|
|
19
|
-
|
|
20
|
-
>>> ## Basic tests
|
|
21
|
-
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)
|
|
22
|
-
>>> adjusted = median_blur_image(image, kernel_size=7, iterations=1)
|
|
23
|
-
>>> adjusted.tolist()
|
|
24
|
-
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
25
|
-
>>> adjusted.shape == image.shape
|
|
26
|
-
True
|
|
27
|
-
>>> adjusted.dtype == image.dtype
|
|
28
|
-
True
|
|
29
|
-
|
|
30
|
-
>>> median_blur_image(image, kernel_size=3, iterations=1).tolist()
|
|
31
|
-
[[2, 3, 3], [4, 5, 6], [7, 7, 8]]
|
|
32
|
-
>>> median_blur_image(image, kernel_size=3, iterations=2).tolist()
|
|
33
|
-
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
34
|
-
>>> median_blur_image(image, kernel_size=3, iterations=5).tolist()
|
|
35
|
-
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
36
|
-
|
|
37
|
-
>>> ## Test invalid inputs
|
|
38
|
-
>>> median_blur_image("not an image")
|
|
39
|
-
Traceback (most recent call last):
|
|
40
|
-
...
|
|
41
|
-
AssertionError: Image must be a numpy array
|
|
42
|
-
"""
|
|
43
|
-
# Check input data
|
|
44
|
-
check_image(image, ignore_dtype=True)
|
|
45
|
-
|
|
46
|
-
# Apply median blur
|
|
47
|
-
for _ in range(iterations):
|
|
48
|
-
image = cv2.medianBlur(image, kernel_size)
|
|
49
|
-
|
|
50
|
-
# Return the image
|
|
51
|
-
return image
|
|
52
|
-
|
|
1
|
+
|
|
2
|
+
# pyright: reportUnusedImport=false
|
|
3
|
+
# ruff: noqa: F401
|
|
4
|
+
|
|
5
|
+
# Imports
|
|
6
|
+
from .common import Any, NDArray, check_image, cv2, np
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Functions
|
|
10
|
+
def median_blur_image(image: NDArray[Any], kernel_size: int = 7, iterations: int = 1) -> NDArray[Any]:
|
|
11
|
+
""" Apply median blur to an image.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
image (NDArray[Any]): Image to apply median blur
|
|
15
|
+
kernel_size (int): Kernel size for the median blur
|
|
16
|
+
iterations (int): Number of iterations for the median blur
|
|
17
|
+
Returns:
|
|
18
|
+
NDArray[Any]: Image with median blur applied
|
|
19
|
+
|
|
20
|
+
>>> ## Basic tests
|
|
21
|
+
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)
|
|
22
|
+
>>> adjusted = median_blur_image(image, kernel_size=7, iterations=1)
|
|
23
|
+
>>> adjusted.tolist()
|
|
24
|
+
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
25
|
+
>>> adjusted.shape == image.shape
|
|
26
|
+
True
|
|
27
|
+
>>> adjusted.dtype == image.dtype
|
|
28
|
+
True
|
|
29
|
+
|
|
30
|
+
>>> median_blur_image(image, kernel_size=3, iterations=1).tolist()
|
|
31
|
+
[[2, 3, 3], [4, 5, 6], [7, 7, 8]]
|
|
32
|
+
>>> median_blur_image(image, kernel_size=3, iterations=2).tolist()
|
|
33
|
+
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
34
|
+
>>> median_blur_image(image, kernel_size=3, iterations=5).tolist()
|
|
35
|
+
[[3, 3, 3], [4, 5, 6], [7, 7, 7]]
|
|
36
|
+
|
|
37
|
+
>>> ## Test invalid inputs
|
|
38
|
+
>>> median_blur_image("not an image")
|
|
39
|
+
Traceback (most recent call last):
|
|
40
|
+
...
|
|
41
|
+
AssertionError: Image must be a numpy array
|
|
42
|
+
"""
|
|
43
|
+
# Check input data
|
|
44
|
+
check_image(image, ignore_dtype=True)
|
|
45
|
+
|
|
46
|
+
# Apply median blur
|
|
47
|
+
for _ in range(iterations):
|
|
48
|
+
image = cv2.medianBlur(image, kernel_size)
|
|
49
|
+
|
|
50
|
+
# Return the image
|
|
51
|
+
return image
|
|
52
|
+
|