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,51 +1,51 @@
|
|
|
1
|
-
""" Load configuration from the set.py file and handle some special cases.
|
|
2
|
-
|
|
3
|
-
Proper way to get the configuration is by importing this module, not the set.py file directly.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
# pyright: reportUnknownMemberType=false
|
|
7
|
-
# pyright: reportUnknownVariableType=false
|
|
8
|
-
# pyright: reportMissingTypeStubs=false
|
|
9
|
-
|
|
10
|
-
# Imports
|
|
11
|
-
import os
|
|
12
|
-
from typing import Any
|
|
13
|
-
|
|
14
|
-
from .set import DataScienceConfig
|
|
15
|
-
|
|
16
|
-
# Special cases
|
|
17
|
-
# Hide GPU when using CPU
|
|
18
|
-
if DataScienceConfig.TENSORFLOW_DEVICE.lower().startswith("/cpu"):
|
|
19
|
-
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
|
20
|
-
|
|
21
|
-
# Precise which GPU we use
|
|
22
|
-
elif DataScienceConfig.TENSORFLOW_DEVICE.lower().startswith("/gpu"):
|
|
23
|
-
os.environ["CUDA_VISIBLE_DEVICES"] = DataScienceConfig.TENSORFLOW_DEVICE.split(":")[-1]
|
|
24
|
-
|
|
25
|
-
# Configure TensorFlow (if available)
|
|
26
|
-
try:
|
|
27
|
-
from tensorflow import config as tf_config
|
|
28
|
-
|
|
29
|
-
# Get the physical devices
|
|
30
|
-
physical_devices: list[Any] = tf_config.list_physical_devices("GPU")
|
|
31
|
-
|
|
32
|
-
# Configure TensorFlow GPU memory management to allocate memory dynamically
|
|
33
|
-
# This prevents TensorFlow from allocating all GPU memory upfront
|
|
34
|
-
# Instead, memory will grow as needed, allowing better resource sharing
|
|
35
|
-
for device in physical_devices:
|
|
36
|
-
tf_config.experimental.set_memory_growth(device, True)
|
|
37
|
-
|
|
38
|
-
# Disable eager execution mode in TensorFlow
|
|
39
|
-
# This improves performance by allowing TensorFlow to create an optimized graph
|
|
40
|
-
# of operations instead of executing operations one by one (at the cost of debugging difficulty)
|
|
41
|
-
tf_config.run_functions_eagerly(False)
|
|
42
|
-
except ImportError:
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
# Enable mixed precision training (if available)
|
|
46
|
-
try:
|
|
47
|
-
from keras import mixed_precision
|
|
48
|
-
mixed_precision.set_global_policy(DataScienceConfig.MIXED_PRECISION_POLICY)
|
|
49
|
-
except ImportError:
|
|
50
|
-
pass
|
|
51
|
-
|
|
1
|
+
""" Load configuration from the set.py file and handle some special cases.
|
|
2
|
+
|
|
3
|
+
Proper way to get the configuration is by importing this module, not the set.py file directly.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# pyright: reportUnknownMemberType=false
|
|
7
|
+
# pyright: reportUnknownVariableType=false
|
|
8
|
+
# pyright: reportMissingTypeStubs=false
|
|
9
|
+
|
|
10
|
+
# Imports
|
|
11
|
+
import os
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from .set import DataScienceConfig
|
|
15
|
+
|
|
16
|
+
# Special cases
|
|
17
|
+
# Hide GPU when using CPU
|
|
18
|
+
if DataScienceConfig.TENSORFLOW_DEVICE.lower().startswith("/cpu"):
|
|
19
|
+
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
|
|
20
|
+
|
|
21
|
+
# Precise which GPU we use
|
|
22
|
+
elif DataScienceConfig.TENSORFLOW_DEVICE.lower().startswith("/gpu"):
|
|
23
|
+
os.environ["CUDA_VISIBLE_DEVICES"] = DataScienceConfig.TENSORFLOW_DEVICE.split(":")[-1]
|
|
24
|
+
|
|
25
|
+
# Configure TensorFlow (if available)
|
|
26
|
+
try:
|
|
27
|
+
from tensorflow import config as tf_config
|
|
28
|
+
|
|
29
|
+
# Get the physical devices
|
|
30
|
+
physical_devices: list[Any] = tf_config.list_physical_devices("GPU")
|
|
31
|
+
|
|
32
|
+
# Configure TensorFlow GPU memory management to allocate memory dynamically
|
|
33
|
+
# This prevents TensorFlow from allocating all GPU memory upfront
|
|
34
|
+
# Instead, memory will grow as needed, allowing better resource sharing
|
|
35
|
+
for device in physical_devices:
|
|
36
|
+
tf_config.experimental.set_memory_growth(device, True)
|
|
37
|
+
|
|
38
|
+
# Disable eager execution mode in TensorFlow
|
|
39
|
+
# This improves performance by allowing TensorFlow to create an optimized graph
|
|
40
|
+
# of operations instead of executing operations one by one (at the cost of debugging difficulty)
|
|
41
|
+
tf_config.run_functions_eagerly(False)
|
|
42
|
+
except ImportError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
# Enable mixed precision training (if available)
|
|
46
|
+
try:
|
|
47
|
+
from keras import mixed_precision
|
|
48
|
+
mixed_precision.set_global_policy(DataScienceConfig.MIXED_PRECISION_POLICY)
|
|
49
|
+
except ImportError:
|
|
50
|
+
pass
|
|
51
|
+
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
# Imports
|
|
3
|
-
from .auto_contrast import auto_contrast_image
|
|
4
|
-
from .axis_flip import flip_image
|
|
5
|
-
from .bias_field_correction import bias_field_correction_image
|
|
6
|
-
from .binary_threshold import binary_threshold_image
|
|
7
|
-
from .blur import blur_image
|
|
8
|
-
from .brightness import brightness_image
|
|
9
|
-
from .canny import canny_image
|
|
10
|
-
from .clahe import clahe_image
|
|
11
|
-
from .contrast import contrast_image
|
|
12
|
-
from .curvature_flow_filter import curvature_flow_filter_image
|
|
13
|
-
from .denoise import (
|
|
14
|
-
adaptive_denoise_image,
|
|
15
|
-
bilateral_denoise_image,
|
|
16
|
-
nlm_denoise_image,
|
|
17
|
-
tv_denoise_image,
|
|
18
|
-
wavelet_denoise_image,
|
|
19
|
-
)
|
|
20
|
-
from .invert import invert_image
|
|
21
|
-
from .laplacian import laplacian_image
|
|
22
|
-
from .median_blur import median_blur_image
|
|
23
|
-
from .noise import noise_image
|
|
24
|
-
from .normalize import normalize_image
|
|
25
|
-
from .random_erase import random_erase_image
|
|
26
|
-
from .resize import resize_image
|
|
27
|
-
from .rotation import rotate_image
|
|
28
|
-
from .salt_pepper import salt_pepper_image
|
|
29
|
-
from .sharpening import sharpen_image
|
|
30
|
-
from .shearing import shear_image
|
|
31
|
-
from .threshold import threshold_image
|
|
32
|
-
from .translation import translate_image
|
|
33
|
-
from .zoom import zoom_image
|
|
34
|
-
|
|
35
|
-
__all__ = [
|
|
36
|
-
"adaptive_denoise_image",
|
|
37
|
-
"auto_contrast_image",
|
|
38
|
-
"bias_field_correction_image",
|
|
39
|
-
"bilateral_denoise_image",
|
|
40
|
-
"binary_threshold_image",
|
|
41
|
-
"blur_image",
|
|
42
|
-
"brightness_image",
|
|
43
|
-
"canny_image",
|
|
44
|
-
"clahe_image",
|
|
45
|
-
"contrast_image",
|
|
46
|
-
"curvature_flow_filter_image",
|
|
47
|
-
"flip_image",
|
|
48
|
-
"invert_image",
|
|
49
|
-
"laplacian_image",
|
|
50
|
-
"median_blur_image",
|
|
51
|
-
"nlm_denoise_image",
|
|
52
|
-
"noise_image",
|
|
53
|
-
"normalize_image",
|
|
54
|
-
"random_erase_image",
|
|
55
|
-
"resize_image",
|
|
56
|
-
"rotate_image",
|
|
57
|
-
"salt_pepper_image",
|
|
58
|
-
"sharpen_image",
|
|
59
|
-
"shear_image",
|
|
60
|
-
"threshold_image",
|
|
61
|
-
"translate_image",
|
|
62
|
-
"tv_denoise_image",
|
|
63
|
-
"wavelet_denoise_image",
|
|
64
|
-
"zoom_image",
|
|
65
|
-
]
|
|
66
|
-
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
from .auto_contrast import auto_contrast_image
|
|
4
|
+
from .axis_flip import flip_image
|
|
5
|
+
from .bias_field_correction import bias_field_correction_image
|
|
6
|
+
from .binary_threshold import binary_threshold_image
|
|
7
|
+
from .blur import blur_image
|
|
8
|
+
from .brightness import brightness_image
|
|
9
|
+
from .canny import canny_image
|
|
10
|
+
from .clahe import clahe_image
|
|
11
|
+
from .contrast import contrast_image
|
|
12
|
+
from .curvature_flow_filter import curvature_flow_filter_image
|
|
13
|
+
from .denoise import (
|
|
14
|
+
adaptive_denoise_image,
|
|
15
|
+
bilateral_denoise_image,
|
|
16
|
+
nlm_denoise_image,
|
|
17
|
+
tv_denoise_image,
|
|
18
|
+
wavelet_denoise_image,
|
|
19
|
+
)
|
|
20
|
+
from .invert import invert_image
|
|
21
|
+
from .laplacian import laplacian_image
|
|
22
|
+
from .median_blur import median_blur_image
|
|
23
|
+
from .noise import noise_image
|
|
24
|
+
from .normalize import normalize_image
|
|
25
|
+
from .random_erase import random_erase_image
|
|
26
|
+
from .resize import resize_image
|
|
27
|
+
from .rotation import rotate_image
|
|
28
|
+
from .salt_pepper import salt_pepper_image
|
|
29
|
+
from .sharpening import sharpen_image
|
|
30
|
+
from .shearing import shear_image
|
|
31
|
+
from .threshold import threshold_image
|
|
32
|
+
from .translation import translate_image
|
|
33
|
+
from .zoom import zoom_image
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"adaptive_denoise_image",
|
|
37
|
+
"auto_contrast_image",
|
|
38
|
+
"bias_field_correction_image",
|
|
39
|
+
"bilateral_denoise_image",
|
|
40
|
+
"binary_threshold_image",
|
|
41
|
+
"blur_image",
|
|
42
|
+
"brightness_image",
|
|
43
|
+
"canny_image",
|
|
44
|
+
"clahe_image",
|
|
45
|
+
"contrast_image",
|
|
46
|
+
"curvature_flow_filter_image",
|
|
47
|
+
"flip_image",
|
|
48
|
+
"invert_image",
|
|
49
|
+
"laplacian_image",
|
|
50
|
+
"median_blur_image",
|
|
51
|
+
"nlm_denoise_image",
|
|
52
|
+
"noise_image",
|
|
53
|
+
"normalize_image",
|
|
54
|
+
"random_erase_image",
|
|
55
|
+
"resize_image",
|
|
56
|
+
"rotate_image",
|
|
57
|
+
"salt_pepper_image",
|
|
58
|
+
"sharpen_image",
|
|
59
|
+
"shear_image",
|
|
60
|
+
"threshold_image",
|
|
61
|
+
"translate_image",
|
|
62
|
+
"tv_denoise_image",
|
|
63
|
+
"wavelet_denoise_image",
|
|
64
|
+
"zoom_image",
|
|
65
|
+
]
|
|
66
|
+
|
|
@@ -1,79 +1,79 @@
|
|
|
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 auto_contrast_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
11
|
-
""" Adjust the contrast of an image.
|
|
12
|
-
|
|
13
|
-
Args:
|
|
14
|
-
image (NDArray[Any]): Image to adjust contrast
|
|
15
|
-
ignore_dtype (bool): Ignore the dtype check
|
|
16
|
-
Returns:
|
|
17
|
-
NDArray[Any]: Image with adjusted contrast
|
|
18
|
-
|
|
19
|
-
>>> ## Basic tests
|
|
20
|
-
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)
|
|
21
|
-
>>> adjusted = auto_contrast_image(image)
|
|
22
|
-
>>> adjusted.tolist()
|
|
23
|
-
[[0, 36, 73], [109, 146, 182], [219, 255, 255]]
|
|
24
|
-
>>> adjusted.shape == image.shape
|
|
25
|
-
True
|
|
26
|
-
>>> adjusted.dtype == image.dtype
|
|
27
|
-
True
|
|
28
|
-
|
|
29
|
-
>>> ## Test invalid inputs
|
|
30
|
-
>>> auto_contrast_image("not an image")
|
|
31
|
-
Traceback (most recent call last):
|
|
32
|
-
...
|
|
33
|
-
AssertionError: Image must be a numpy array
|
|
34
|
-
"""
|
|
35
|
-
# Check input data
|
|
36
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
37
|
-
|
|
38
|
-
# Perform histogram clipping
|
|
39
|
-
clip_hist_percent: float = 1.0
|
|
40
|
-
|
|
41
|
-
# Calculate the histogram of the image
|
|
42
|
-
hist: NDArray[Any] = cv2.calcHist([image], [0], None, [256], [0, 256])
|
|
43
|
-
|
|
44
|
-
# Create an accumulator list to store the cumulative histogram
|
|
45
|
-
accumulator: list[float] = []
|
|
46
|
-
accumulator.append(hist[0])
|
|
47
|
-
for i in range(1, 256):
|
|
48
|
-
accumulator.append(accumulator[i - 1] + hist[i])
|
|
49
|
-
|
|
50
|
-
# Find the maximum value in the accumulator
|
|
51
|
-
max_value: float = accumulator[-1]
|
|
52
|
-
|
|
53
|
-
# Calculate the clipping threshold
|
|
54
|
-
clip_hist_percent = clip_hist_percent * (max_value / 100.0)
|
|
55
|
-
clip_hist_percent = clip_hist_percent / 2.0
|
|
56
|
-
|
|
57
|
-
# Find the minimum and maximum gray levels after clipping
|
|
58
|
-
min_gray: int = 0
|
|
59
|
-
while accumulator[min_gray] < clip_hist_percent:
|
|
60
|
-
min_gray = min_gray + 1
|
|
61
|
-
max_gray: int = 256 - 1
|
|
62
|
-
while (max_gray >= 0 and accumulator[max_gray] >= (max_value - clip_hist_percent)):
|
|
63
|
-
max_gray = max_gray - 1
|
|
64
|
-
|
|
65
|
-
# Calculate the input range after clipping
|
|
66
|
-
input_range: int = max_gray - min_gray
|
|
67
|
-
|
|
68
|
-
# If the input range is 0, return the original image
|
|
69
|
-
if input_range == 0:
|
|
70
|
-
return image
|
|
71
|
-
|
|
72
|
-
# Calculate the scaling factors for contrast adjustment
|
|
73
|
-
alpha: float = (256 - 1) / input_range
|
|
74
|
-
beta: float = -min_gray * alpha
|
|
75
|
-
|
|
76
|
-
# Apply the contrast adjustment
|
|
77
|
-
adjusted: NDArray[Any] = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
|
|
78
|
-
return adjusted
|
|
79
|
-
|
|
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 auto_contrast_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
11
|
+
""" Adjust the contrast of an image.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
image (NDArray[Any]): Image to adjust contrast
|
|
15
|
+
ignore_dtype (bool): Ignore the dtype check
|
|
16
|
+
Returns:
|
|
17
|
+
NDArray[Any]: Image with adjusted contrast
|
|
18
|
+
|
|
19
|
+
>>> ## Basic tests
|
|
20
|
+
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)
|
|
21
|
+
>>> adjusted = auto_contrast_image(image)
|
|
22
|
+
>>> adjusted.tolist()
|
|
23
|
+
[[0, 36, 73], [109, 146, 182], [219, 255, 255]]
|
|
24
|
+
>>> adjusted.shape == image.shape
|
|
25
|
+
True
|
|
26
|
+
>>> adjusted.dtype == image.dtype
|
|
27
|
+
True
|
|
28
|
+
|
|
29
|
+
>>> ## Test invalid inputs
|
|
30
|
+
>>> auto_contrast_image("not an image")
|
|
31
|
+
Traceback (most recent call last):
|
|
32
|
+
...
|
|
33
|
+
AssertionError: Image must be a numpy array
|
|
34
|
+
"""
|
|
35
|
+
# Check input data
|
|
36
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
37
|
+
|
|
38
|
+
# Perform histogram clipping
|
|
39
|
+
clip_hist_percent: float = 1.0
|
|
40
|
+
|
|
41
|
+
# Calculate the histogram of the image
|
|
42
|
+
hist: NDArray[Any] = cv2.calcHist([image], [0], None, [256], [0, 256])
|
|
43
|
+
|
|
44
|
+
# Create an accumulator list to store the cumulative histogram
|
|
45
|
+
accumulator: list[float] = []
|
|
46
|
+
accumulator.append(hist[0])
|
|
47
|
+
for i in range(1, 256):
|
|
48
|
+
accumulator.append(accumulator[i - 1] + hist[i])
|
|
49
|
+
|
|
50
|
+
# Find the maximum value in the accumulator
|
|
51
|
+
max_value: float = accumulator[-1]
|
|
52
|
+
|
|
53
|
+
# Calculate the clipping threshold
|
|
54
|
+
clip_hist_percent = clip_hist_percent * (max_value / 100.0)
|
|
55
|
+
clip_hist_percent = clip_hist_percent / 2.0
|
|
56
|
+
|
|
57
|
+
# Find the minimum and maximum gray levels after clipping
|
|
58
|
+
min_gray: int = 0
|
|
59
|
+
while accumulator[min_gray] < clip_hist_percent:
|
|
60
|
+
min_gray = min_gray + 1
|
|
61
|
+
max_gray: int = 256 - 1
|
|
62
|
+
while (max_gray >= 0 and accumulator[max_gray] >= (max_value - clip_hist_percent)):
|
|
63
|
+
max_gray = max_gray - 1
|
|
64
|
+
|
|
65
|
+
# Calculate the input range after clipping
|
|
66
|
+
input_range: int = max_gray - min_gray
|
|
67
|
+
|
|
68
|
+
# If the input range is 0, return the original image
|
|
69
|
+
if input_range == 0:
|
|
70
|
+
return image
|
|
71
|
+
|
|
72
|
+
# Calculate the scaling factors for contrast adjustment
|
|
73
|
+
alpha: float = (256 - 1) / input_range
|
|
74
|
+
beta: float = -min_gray * alpha
|
|
75
|
+
|
|
76
|
+
# Apply the contrast adjustment
|
|
77
|
+
adjusted: NDArray[Any] = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
|
|
78
|
+
return adjusted
|
|
79
|
+
|
|
@@ -1,58 +1,58 @@
|
|
|
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
|
-
|
|
11
|
-
# Functions
|
|
12
|
-
def flip_image(
|
|
13
|
-
image: NDArray[Any], axis: Literal["horizontal", "vertical", "both"], ignore_dtype: bool = True
|
|
14
|
-
) -> NDArray[Any]:
|
|
15
|
-
""" Flip an image along specified axis
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
image (NDArray[Any]): Image to flip
|
|
19
|
-
axis (str): Axis along which to flip ("horizontal" or "vertical" or "both")
|
|
20
|
-
ignore_dtype (bool): Ignore the dtype check
|
|
21
|
-
Returns:
|
|
22
|
-
NDArray[Any]: Flipped image
|
|
23
|
-
|
|
24
|
-
>>> ## Basic tests
|
|
25
|
-
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
26
|
-
>>> flip_image(image, "horizontal").tolist()
|
|
27
|
-
[[3, 2, 1], [6, 5, 4], [9, 8, 7]]
|
|
28
|
-
|
|
29
|
-
>>> flip_image(image, "vertical").tolist()
|
|
30
|
-
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
|
|
31
|
-
|
|
32
|
-
>>> flip_image(image, "both").tolist()
|
|
33
|
-
[[9, 8, 7], [6, 5, 4], [3, 2, 1]]
|
|
34
|
-
|
|
35
|
-
>>> ## Test invalid inputs
|
|
36
|
-
>>> flip_image(image, "diagonal")
|
|
37
|
-
Traceback (most recent call last):
|
|
38
|
-
AssertionError: axis must be either 'horizontal' or 'vertical' or 'both', got 'diagonal'
|
|
39
|
-
|
|
40
|
-
>>> flip_image("not an image", "horizontal")
|
|
41
|
-
Traceback (most recent call last):
|
|
42
|
-
...
|
|
43
|
-
AssertionError: Image must be a numpy array
|
|
44
|
-
"""
|
|
45
|
-
# Check input data
|
|
46
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
47
|
-
assert axis in ("horizontal", "vertical", "both"), (
|
|
48
|
-
f"axis must be either 'horizontal' or 'vertical' or 'both', got '{axis}'"
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
# Apply the flip
|
|
52
|
-
if axis == "horizontal":
|
|
53
|
-
return cv2.flip(image, 1) # 1 for horizontal flip
|
|
54
|
-
elif axis == "vertical":
|
|
55
|
-
return cv2.flip(image, 0) # 0 for vertical flip
|
|
56
|
-
else:
|
|
57
|
-
return cv2.flip(image, -1) # -1 for both flips
|
|
58
|
-
|
|
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
|
+
|
|
11
|
+
# Functions
|
|
12
|
+
def flip_image(
|
|
13
|
+
image: NDArray[Any], axis: Literal["horizontal", "vertical", "both"], ignore_dtype: bool = True
|
|
14
|
+
) -> NDArray[Any]:
|
|
15
|
+
""" Flip an image along specified axis
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
image (NDArray[Any]): Image to flip
|
|
19
|
+
axis (str): Axis along which to flip ("horizontal" or "vertical" or "both")
|
|
20
|
+
ignore_dtype (bool): Ignore the dtype check
|
|
21
|
+
Returns:
|
|
22
|
+
NDArray[Any]: Flipped image
|
|
23
|
+
|
|
24
|
+
>>> ## Basic tests
|
|
25
|
+
>>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
|
26
|
+
>>> flip_image(image, "horizontal").tolist()
|
|
27
|
+
[[3, 2, 1], [6, 5, 4], [9, 8, 7]]
|
|
28
|
+
|
|
29
|
+
>>> flip_image(image, "vertical").tolist()
|
|
30
|
+
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
|
|
31
|
+
|
|
32
|
+
>>> flip_image(image, "both").tolist()
|
|
33
|
+
[[9, 8, 7], [6, 5, 4], [3, 2, 1]]
|
|
34
|
+
|
|
35
|
+
>>> ## Test invalid inputs
|
|
36
|
+
>>> flip_image(image, "diagonal")
|
|
37
|
+
Traceback (most recent call last):
|
|
38
|
+
AssertionError: axis must be either 'horizontal' or 'vertical' or 'both', got 'diagonal'
|
|
39
|
+
|
|
40
|
+
>>> flip_image("not an image", "horizontal")
|
|
41
|
+
Traceback (most recent call last):
|
|
42
|
+
...
|
|
43
|
+
AssertionError: Image must be a numpy array
|
|
44
|
+
"""
|
|
45
|
+
# Check input data
|
|
46
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
47
|
+
assert axis in ("horizontal", "vertical", "both"), (
|
|
48
|
+
f"axis must be either 'horizontal' or 'vertical' or 'both', got '{axis}'"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Apply the flip
|
|
52
|
+
if axis == "horizontal":
|
|
53
|
+
return cv2.flip(image, 1) # 1 for horizontal flip
|
|
54
|
+
elif axis == "vertical":
|
|
55
|
+
return cv2.flip(image, 0) # 0 for vertical flip
|
|
56
|
+
else:
|
|
57
|
+
return cv2.flip(image, -1) # -1 for both flips
|
|
58
|
+
|
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
# pyright: reportUnknownMemberType=false
|
|
3
|
-
# pyright: reportUnknownArgumentType=false
|
|
4
|
-
# pyright: reportUnknownVariableType=false
|
|
5
|
-
|
|
6
|
-
# Imports
|
|
7
|
-
import SimpleITK as Sitk
|
|
8
|
-
|
|
9
|
-
from .common import Any, NDArray, check_image, np
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Functions
|
|
13
|
-
def bias_field_correction_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
14
|
-
""" Apply a bias field correction to an image. (N4 Filter)
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
image (NDArray[Any]): Image to apply the bias field correction (can't be 8-bit unsigned integer)
|
|
18
|
-
ignore_dtype (bool): Ignore the dtype check
|
|
19
|
-
Returns:
|
|
20
|
-
NDArray[Any]: Image with the curvature flow filter applied
|
|
21
|
-
|
|
22
|
-
>>> ## Basic tests
|
|
23
|
-
>>> image = np.random.randint(0, 255, size=(10,10), dtype=np.uint8) / 255
|
|
24
|
-
>>> corrected = bias_field_correction_image(image)
|
|
25
|
-
>>> corrected.shape == image.shape
|
|
26
|
-
True
|
|
27
|
-
>>> corrected.dtype == np.float64
|
|
28
|
-
True
|
|
29
|
-
|
|
30
|
-
>>> ## Test invalid inputs
|
|
31
|
-
>>> bias_field_correction_image("not an image")
|
|
32
|
-
Traceback (most recent call last):
|
|
33
|
-
...
|
|
34
|
-
AssertionError: Image must be a numpy array
|
|
35
|
-
"""
|
|
36
|
-
# Check input data
|
|
37
|
-
check_image(image, ignore_dtype=ignore_dtype)
|
|
38
|
-
|
|
39
|
-
# If the image is 3D, convert to grayscale first
|
|
40
|
-
if image.ndim == 3:
|
|
41
|
-
image = np.mean(image, axis=-1)
|
|
42
|
-
|
|
43
|
-
# Convert numpy array to SimpleITK image
|
|
44
|
-
image_sitk: Sitk.Image = Sitk.GetImageFromArray(image)
|
|
45
|
-
|
|
46
|
-
# Create binary mask of the head region
|
|
47
|
-
transformed: Sitk.Image = Sitk.RescaleIntensity(image_sitk) # Normalize intensities
|
|
48
|
-
transformed = Sitk.LiThreshold(transformed, 0, 1) # Apply Li thresholding
|
|
49
|
-
head_mask: Sitk.Image = transformed
|
|
50
|
-
|
|
51
|
-
# Downsample images to speed up bias field estimation
|
|
52
|
-
shrink_factor: int = 4 # Reduce image size by factor of 4
|
|
53
|
-
input_image: Sitk.Image = Sitk.Shrink(
|
|
54
|
-
image_sitk,
|
|
55
|
-
[shrink_factor] * image_sitk.GetDimension() # Apply shrink factor to all dimensions
|
|
56
|
-
)
|
|
57
|
-
mask_image: Sitk.Image = Sitk.Shrink(
|
|
58
|
-
head_mask,
|
|
59
|
-
[shrink_factor] * image_sitk.GetDimension()
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
# Apply N4 bias field correction
|
|
63
|
-
corrector = Sitk.N4BiasFieldCorrectionImageFilter()
|
|
64
|
-
corrector.Execute(input_image, mask_image)
|
|
65
|
-
|
|
66
|
-
# Get estimated bias field and apply correction
|
|
67
|
-
log_bias_field: Sitk.Image = Sitk.Cast(
|
|
68
|
-
corrector.GetLogBiasFieldAsImage(image_sitk), Sitk.sitkFloat64
|
|
69
|
-
)
|
|
70
|
-
corrected_image_full_resolution: Sitk.Image = image_sitk / Sitk.Exp(log_bias_field)
|
|
71
|
-
|
|
72
|
-
# Convert back to numpy array and return
|
|
73
|
-
return Sitk.GetArrayFromImage(corrected_image_full_resolution)
|
|
74
|
-
|
|
1
|
+
|
|
2
|
+
# pyright: reportUnknownMemberType=false
|
|
3
|
+
# pyright: reportUnknownArgumentType=false
|
|
4
|
+
# pyright: reportUnknownVariableType=false
|
|
5
|
+
|
|
6
|
+
# Imports
|
|
7
|
+
import SimpleITK as Sitk
|
|
8
|
+
|
|
9
|
+
from .common import Any, NDArray, check_image, np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Functions
|
|
13
|
+
def bias_field_correction_image(image: NDArray[Any], ignore_dtype: bool = False) -> NDArray[Any]:
|
|
14
|
+
""" Apply a bias field correction to an image. (N4 Filter)
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
image (NDArray[Any]): Image to apply the bias field correction (can't be 8-bit unsigned integer)
|
|
18
|
+
ignore_dtype (bool): Ignore the dtype check
|
|
19
|
+
Returns:
|
|
20
|
+
NDArray[Any]: Image with the curvature flow filter applied
|
|
21
|
+
|
|
22
|
+
>>> ## Basic tests
|
|
23
|
+
>>> image = np.random.randint(0, 255, size=(10,10), dtype=np.uint8) / 255
|
|
24
|
+
>>> corrected = bias_field_correction_image(image)
|
|
25
|
+
>>> corrected.shape == image.shape
|
|
26
|
+
True
|
|
27
|
+
>>> corrected.dtype == np.float64
|
|
28
|
+
True
|
|
29
|
+
|
|
30
|
+
>>> ## Test invalid inputs
|
|
31
|
+
>>> bias_field_correction_image("not an image")
|
|
32
|
+
Traceback (most recent call last):
|
|
33
|
+
...
|
|
34
|
+
AssertionError: Image must be a numpy array
|
|
35
|
+
"""
|
|
36
|
+
# Check input data
|
|
37
|
+
check_image(image, ignore_dtype=ignore_dtype)
|
|
38
|
+
|
|
39
|
+
# If the image is 3D, convert to grayscale first
|
|
40
|
+
if image.ndim == 3:
|
|
41
|
+
image = np.mean(image, axis=-1)
|
|
42
|
+
|
|
43
|
+
# Convert numpy array to SimpleITK image
|
|
44
|
+
image_sitk: Sitk.Image = Sitk.GetImageFromArray(image)
|
|
45
|
+
|
|
46
|
+
# Create binary mask of the head region
|
|
47
|
+
transformed: Sitk.Image = Sitk.RescaleIntensity(image_sitk) # Normalize intensities
|
|
48
|
+
transformed = Sitk.LiThreshold(transformed, 0, 1) # Apply Li thresholding
|
|
49
|
+
head_mask: Sitk.Image = transformed
|
|
50
|
+
|
|
51
|
+
# Downsample images to speed up bias field estimation
|
|
52
|
+
shrink_factor: int = 4 # Reduce image size by factor of 4
|
|
53
|
+
input_image: Sitk.Image = Sitk.Shrink(
|
|
54
|
+
image_sitk,
|
|
55
|
+
[shrink_factor] * image_sitk.GetDimension() # Apply shrink factor to all dimensions
|
|
56
|
+
)
|
|
57
|
+
mask_image: Sitk.Image = Sitk.Shrink(
|
|
58
|
+
head_mask,
|
|
59
|
+
[shrink_factor] * image_sitk.GetDimension()
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Apply N4 bias field correction
|
|
63
|
+
corrector = Sitk.N4BiasFieldCorrectionImageFilter()
|
|
64
|
+
corrector.Execute(input_image, mask_image)
|
|
65
|
+
|
|
66
|
+
# Get estimated bias field and apply correction
|
|
67
|
+
log_bias_field: Sitk.Image = Sitk.Cast(
|
|
68
|
+
corrector.GetLogBiasFieldAsImage(image_sitk), Sitk.sitkFloat64
|
|
69
|
+
)
|
|
70
|
+
corrected_image_full_resolution: Sitk.Image = image_sitk / Sitk.Exp(log_bias_field)
|
|
71
|
+
|
|
72
|
+
# Convert back to numpy array and return
|
|
73
|
+
return Sitk.GetArrayFromImage(corrected_image_full_resolution)
|
|
74
|
+
|