stouputils 1.14.2__py3-none-any.whl → 1.15.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.
Files changed (113) hide show
  1. stouputils/continuous_delivery/pypi.py +1 -1
  2. stouputils/continuous_delivery/pypi.pyi +3 -2
  3. stouputils/data_science/config/get.py +51 -51
  4. stouputils/data_science/data_processing/image/__init__.py +66 -66
  5. stouputils/data_science/data_processing/image/auto_contrast.py +79 -79
  6. stouputils/data_science/data_processing/image/axis_flip.py +58 -58
  7. stouputils/data_science/data_processing/image/bias_field_correction.py +74 -74
  8. stouputils/data_science/data_processing/image/binary_threshold.py +73 -73
  9. stouputils/data_science/data_processing/image/blur.py +59 -59
  10. stouputils/data_science/data_processing/image/brightness.py +54 -54
  11. stouputils/data_science/data_processing/image/canny.py +110 -110
  12. stouputils/data_science/data_processing/image/clahe.py +92 -92
  13. stouputils/data_science/data_processing/image/common.py +30 -30
  14. stouputils/data_science/data_processing/image/contrast.py +53 -53
  15. stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -74
  16. stouputils/data_science/data_processing/image/denoise.py +378 -378
  17. stouputils/data_science/data_processing/image/histogram_equalization.py +123 -123
  18. stouputils/data_science/data_processing/image/invert.py +64 -64
  19. stouputils/data_science/data_processing/image/laplacian.py +60 -60
  20. stouputils/data_science/data_processing/image/median_blur.py +52 -52
  21. stouputils/data_science/data_processing/image/noise.py +59 -59
  22. stouputils/data_science/data_processing/image/normalize.py +65 -65
  23. stouputils/data_science/data_processing/image/random_erase.py +66 -66
  24. stouputils/data_science/data_processing/image/resize.py +69 -69
  25. stouputils/data_science/data_processing/image/rotation.py +80 -80
  26. stouputils/data_science/data_processing/image/salt_pepper.py +68 -68
  27. stouputils/data_science/data_processing/image/sharpening.py +55 -55
  28. stouputils/data_science/data_processing/image/shearing.py +64 -64
  29. stouputils/data_science/data_processing/image/threshold.py +64 -64
  30. stouputils/data_science/data_processing/image/translation.py +71 -71
  31. stouputils/data_science/data_processing/image/zoom.py +83 -83
  32. stouputils/data_science/data_processing/image_augmentation.py +118 -118
  33. stouputils/data_science/data_processing/image_preprocess.py +183 -183
  34. stouputils/data_science/data_processing/prosthesis_detection.py +359 -359
  35. stouputils/data_science/data_processing/technique.py +481 -481
  36. stouputils/data_science/dataset/__init__.py +45 -45
  37. stouputils/data_science/dataset/dataset.py +292 -292
  38. stouputils/data_science/dataset/dataset_loader.py +135 -135
  39. stouputils/data_science/dataset/grouping_strategy.py +296 -296
  40. stouputils/data_science/dataset/image_loader.py +100 -100
  41. stouputils/data_science/dataset/xy_tuple.py +696 -696
  42. stouputils/data_science/metric_dictionnary.py +106 -106
  43. stouputils/data_science/mlflow_utils.py +206 -206
  44. stouputils/data_science/models/abstract_model.py +149 -149
  45. stouputils/data_science/models/all.py +85 -85
  46. stouputils/data_science/models/keras/all.py +38 -38
  47. stouputils/data_science/models/keras/convnext.py +62 -62
  48. stouputils/data_science/models/keras/densenet.py +50 -50
  49. stouputils/data_science/models/keras/efficientnet.py +60 -60
  50. stouputils/data_science/models/keras/mobilenet.py +56 -56
  51. stouputils/data_science/models/keras/resnet.py +52 -52
  52. stouputils/data_science/models/keras/squeezenet.py +233 -233
  53. stouputils/data_science/models/keras/vgg.py +42 -42
  54. stouputils/data_science/models/keras/xception.py +38 -38
  55. stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -20
  56. stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -219
  57. stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -148
  58. stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -31
  59. stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -249
  60. stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -66
  61. stouputils/data_science/models/keras_utils/losses/__init__.py +12 -12
  62. stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -56
  63. stouputils/data_science/models/keras_utils/visualizations.py +416 -416
  64. stouputils/data_science/models/sandbox.py +116 -116
  65. stouputils/data_science/range_tuple.py +234 -234
  66. stouputils/data_science/utils.py +285 -285
  67. stouputils/decorators.py +53 -39
  68. stouputils/decorators.pyi +12 -2
  69. stouputils/installer/__init__.py +18 -18
  70. stouputils/installer/linux.py +144 -144
  71. stouputils/installer/main.py +223 -223
  72. stouputils/installer/windows.py +136 -136
  73. stouputils/io.py +16 -9
  74. stouputils/parallel.pyi +12 -7
  75. stouputils/print.py +229 -2
  76. stouputils/print.pyi +92 -3
  77. stouputils/py.typed +1 -1
  78. {stouputils-1.14.2.dist-info → stouputils-1.15.0.dist-info}/METADATA +1 -1
  79. stouputils-1.15.0.dist-info/RECORD +140 -0
  80. {stouputils-1.14.2.dist-info → stouputils-1.15.0.dist-info}/WHEEL +1 -1
  81. stouputils/stouputils/__init__.pyi +0 -15
  82. stouputils/stouputils/_deprecated.pyi +0 -12
  83. stouputils/stouputils/all_doctests.pyi +0 -46
  84. stouputils/stouputils/applications/__init__.pyi +0 -2
  85. stouputils/stouputils/applications/automatic_docs.pyi +0 -106
  86. stouputils/stouputils/applications/upscaler/__init__.pyi +0 -3
  87. stouputils/stouputils/applications/upscaler/config.pyi +0 -18
  88. stouputils/stouputils/applications/upscaler/image.pyi +0 -109
  89. stouputils/stouputils/applications/upscaler/video.pyi +0 -60
  90. stouputils/stouputils/archive.pyi +0 -67
  91. stouputils/stouputils/backup.pyi +0 -109
  92. stouputils/stouputils/collections.pyi +0 -86
  93. stouputils/stouputils/continuous_delivery/__init__.pyi +0 -5
  94. stouputils/stouputils/continuous_delivery/cd_utils.pyi +0 -129
  95. stouputils/stouputils/continuous_delivery/github.pyi +0 -162
  96. stouputils/stouputils/continuous_delivery/pypi.pyi +0 -53
  97. stouputils/stouputils/continuous_delivery/pyproject.pyi +0 -67
  98. stouputils/stouputils/continuous_delivery/stubs.pyi +0 -39
  99. stouputils/stouputils/ctx.pyi +0 -211
  100. stouputils/stouputils/decorators.pyi +0 -252
  101. stouputils/stouputils/image.pyi +0 -172
  102. stouputils/stouputils/installer/__init__.pyi +0 -5
  103. stouputils/stouputils/installer/common.pyi +0 -39
  104. stouputils/stouputils/installer/downloader.pyi +0 -24
  105. stouputils/stouputils/installer/linux.pyi +0 -39
  106. stouputils/stouputils/installer/main.pyi +0 -57
  107. stouputils/stouputils/installer/windows.pyi +0 -31
  108. stouputils/stouputils/io.pyi +0 -213
  109. stouputils/stouputils/parallel.pyi +0 -216
  110. stouputils/stouputils/print.pyi +0 -136
  111. stouputils/stouputils/version_pkg.pyi +0 -15
  112. stouputils-1.14.2.dist-info/RECORD +0 -171
  113. {stouputils-1.14.2.dist-info → stouputils-1.15.0.dist-info}/entry_points.txt +0 -0
@@ -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
+
@@ -1,73 +1,73 @@
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 binary_threshold_image(image: NDArray[Any], threshold: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
- """ Apply binary threshold to an image.
12
-
13
- Args:
14
- image (NDArray[Any]): Image to threshold
15
- threshold (float): Threshold value (between 0 and 1)
16
- ignore_dtype (bool): Ignore the dtype check
17
- Returns:
18
- NDArray[Any]: Thresholded binary image
19
-
20
- >>> ## Basic tests
21
- >>> image = np.array([[100, 150, 200], [50, 125, 175], [25, 75, 225]])
22
- >>> binary_threshold_image(image.astype(np.uint8), 0.5).tolist()
23
- [[0, 255, 255], [0, 0, 255], [0, 0, 255]]
24
-
25
- >>> np.random.seed(42)
26
- >>> img = np.random.randint(0, 256, (4,4), dtype=np.uint8)
27
- >>> thresholded = binary_threshold_image(img, 0.7)
28
- >>> set(np.unique(thresholded).tolist()) <= {0, 255} # Should only contain 0 and 255
29
- True
30
-
31
- >>> rgb = np.random.randint(0, 256, (3,3,3), dtype=np.uint8)
32
- >>> thresh_rgb = binary_threshold_image(rgb, 0.5)
33
- >>> thresh_rgb.shape == rgb.shape
34
- True
35
- >>> set(np.unique(thresh_rgb).tolist()) <= {0, 255}
36
- True
37
-
38
- >>> ## Test invalid inputs
39
- >>> binary_threshold_image("not an image", 0.5)
40
- Traceback (most recent call last):
41
- ...
42
- AssertionError: Image must be a numpy array
43
-
44
- >>> binary_threshold_image(image.astype(np.uint8), "0.5")
45
- Traceback (most recent call last):
46
- ...
47
- AssertionError: threshold must be a number, got <class 'str'>
48
-
49
- >>> binary_threshold_image(image.astype(np.uint8), 1.5)
50
- Traceback (most recent call last):
51
- ...
52
- AssertionError: threshold must be between 0 and 1, got 1.5
53
- """
54
- # Check input data
55
- check_image(image, ignore_dtype=ignore_dtype)
56
- assert isinstance(threshold, float | int), f"threshold must be a number, got {type(threshold)}"
57
- assert 0 <= threshold <= 1, f"threshold must be between 0 and 1, got {threshold}"
58
-
59
- # Convert threshold from 0-1 range to 0-255 range
60
- threshold_value: int = int(threshold * 255)
61
-
62
- # Apply threshold
63
- if len(image.shape) == 2:
64
- # Grayscale image
65
- binary: NDArray[Any] = cv2.threshold(image, threshold_value, 255, cv2.THRESH_BINARY)[1]
66
- else:
67
- # Color image - convert to grayscale first, then back to color
68
- gray: NDArray[Any] = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
69
- binary: NDArray[Any] = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)[1]
70
- binary = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
71
-
72
- return binary
73
-
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 binary_threshold_image(image: NDArray[Any], threshold: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
+ """ Apply binary threshold to an image.
12
+
13
+ Args:
14
+ image (NDArray[Any]): Image to threshold
15
+ threshold (float): Threshold value (between 0 and 1)
16
+ ignore_dtype (bool): Ignore the dtype check
17
+ Returns:
18
+ NDArray[Any]: Thresholded binary image
19
+
20
+ >>> ## Basic tests
21
+ >>> image = np.array([[100, 150, 200], [50, 125, 175], [25, 75, 225]])
22
+ >>> binary_threshold_image(image.astype(np.uint8), 0.5).tolist()
23
+ [[0, 255, 255], [0, 0, 255], [0, 0, 255]]
24
+
25
+ >>> np.random.seed(42)
26
+ >>> img = np.random.randint(0, 256, (4,4), dtype=np.uint8)
27
+ >>> thresholded = binary_threshold_image(img, 0.7)
28
+ >>> set(np.unique(thresholded).tolist()) <= {0, 255} # Should only contain 0 and 255
29
+ True
30
+
31
+ >>> rgb = np.random.randint(0, 256, (3,3,3), dtype=np.uint8)
32
+ >>> thresh_rgb = binary_threshold_image(rgb, 0.5)
33
+ >>> thresh_rgb.shape == rgb.shape
34
+ True
35
+ >>> set(np.unique(thresh_rgb).tolist()) <= {0, 255}
36
+ True
37
+
38
+ >>> ## Test invalid inputs
39
+ >>> binary_threshold_image("not an image", 0.5)
40
+ Traceback (most recent call last):
41
+ ...
42
+ AssertionError: Image must be a numpy array
43
+
44
+ >>> binary_threshold_image(image.astype(np.uint8), "0.5")
45
+ Traceback (most recent call last):
46
+ ...
47
+ AssertionError: threshold must be a number, got <class 'str'>
48
+
49
+ >>> binary_threshold_image(image.astype(np.uint8), 1.5)
50
+ Traceback (most recent call last):
51
+ ...
52
+ AssertionError: threshold must be between 0 and 1, got 1.5
53
+ """
54
+ # Check input data
55
+ check_image(image, ignore_dtype=ignore_dtype)
56
+ assert isinstance(threshold, float | int), f"threshold must be a number, got {type(threshold)}"
57
+ assert 0 <= threshold <= 1, f"threshold must be between 0 and 1, got {threshold}"
58
+
59
+ # Convert threshold from 0-1 range to 0-255 range
60
+ threshold_value: int = int(threshold * 255)
61
+
62
+ # Apply threshold
63
+ if len(image.shape) == 2:
64
+ # Grayscale image
65
+ binary: NDArray[Any] = cv2.threshold(image, threshold_value, 255, cv2.THRESH_BINARY)[1]
66
+ else:
67
+ # Color image - convert to grayscale first, then back to color
68
+ gray: NDArray[Any] = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
69
+ binary: NDArray[Any] = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)[1]
70
+ binary = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)
71
+
72
+ return binary
73
+
@@ -1,59 +1,59 @@
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 blur_image(image: NDArray[Any], blur_strength: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
- """ Apply Gaussian blur to an image.
12
-
13
- Args:
14
- image (NDArray[Any]): Image to blur
15
- blur_strength (float): Strength of the blur
16
- ignore_dtype (bool): Ignore the dtype check
17
- Returns:
18
- NDArray[Any]: Blurred image
19
-
20
- >>> ## Basic tests
21
- >>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
22
- >>> blurred = blur_image(image.astype(np.uint8), 1.5)
23
- >>> blurred.shape == image.shape
24
- True
25
-
26
- >>> img = np.zeros((5,5), dtype=np.uint8)
27
- >>> img[2,2] = 255 # Single bright pixel
28
- >>> blurred = blur_image(img, 1.0)
29
- >>> bool(blurred[2,2] < 255) # Center should be blurred
30
- True
31
-
32
- >>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
33
- >>> blurred_rgb = blur_image(rgb, 1.0)
34
- >>> blurred_rgb.shape == (3,3,3)
35
- True
36
-
37
- >>> ## Test invalid inputs
38
- >>> blur_image("not an image", 1.5)
39
- Traceback (most recent call last):
40
- ...
41
- AssertionError: Image must be a numpy array
42
-
43
- >>> blur_image(image.astype(np.uint8), "1.5")
44
- Traceback (most recent call last):
45
- ...
46
- AssertionError: blur_strength must be a number, got <class 'str'>
47
- """
48
- # Check input data
49
- check_image(image, ignore_dtype=ignore_dtype)
50
- assert isinstance(blur_strength, float | int), f"blur_strength must be a number, got {type(blur_strength)}"
51
-
52
- # Apply Gaussian blur
53
- kernel_size: int = max(3, int(blur_strength * 2) + 1)
54
- if kernel_size % 2 == 0:
55
- kernel_size += 1
56
- blurred_image: NDArray[Any] = cv2.GaussianBlur(image, (kernel_size, kernel_size), 0)
57
-
58
- return blurred_image
59
-
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 blur_image(image: NDArray[Any], blur_strength: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
+ """ Apply Gaussian blur to an image.
12
+
13
+ Args:
14
+ image (NDArray[Any]): Image to blur
15
+ blur_strength (float): Strength of the blur
16
+ ignore_dtype (bool): Ignore the dtype check
17
+ Returns:
18
+ NDArray[Any]: Blurred image
19
+
20
+ >>> ## Basic tests
21
+ >>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
22
+ >>> blurred = blur_image(image.astype(np.uint8), 1.5)
23
+ >>> blurred.shape == image.shape
24
+ True
25
+
26
+ >>> img = np.zeros((5,5), dtype=np.uint8)
27
+ >>> img[2,2] = 255 # Single bright pixel
28
+ >>> blurred = blur_image(img, 1.0)
29
+ >>> bool(blurred[2,2] < 255) # Center should be blurred
30
+ True
31
+
32
+ >>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
33
+ >>> blurred_rgb = blur_image(rgb, 1.0)
34
+ >>> blurred_rgb.shape == (3,3,3)
35
+ True
36
+
37
+ >>> ## Test invalid inputs
38
+ >>> blur_image("not an image", 1.5)
39
+ Traceback (most recent call last):
40
+ ...
41
+ AssertionError: Image must be a numpy array
42
+
43
+ >>> blur_image(image.astype(np.uint8), "1.5")
44
+ Traceback (most recent call last):
45
+ ...
46
+ AssertionError: blur_strength must be a number, got <class 'str'>
47
+ """
48
+ # Check input data
49
+ check_image(image, ignore_dtype=ignore_dtype)
50
+ assert isinstance(blur_strength, float | int), f"blur_strength must be a number, got {type(blur_strength)}"
51
+
52
+ # Apply Gaussian blur
53
+ kernel_size: int = max(3, int(blur_strength * 2) + 1)
54
+ if kernel_size % 2 == 0:
55
+ kernel_size += 1
56
+ blurred_image: NDArray[Any] = cv2.GaussianBlur(image, (kernel_size, kernel_size), 0)
57
+
58
+ return blurred_image
59
+
@@ -1,54 +1,54 @@
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 brightness_image(image: NDArray[Any], brightness_factor: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
- """ Adjust the brightness of an image.
12
-
13
- Args:
14
- image (NDArray[Any]): Image to adjust brightness
15
- brightness_factor (float): Brightness adjustment factor
16
- ignore_dtype (bool): Ignore the dtype check
17
- Returns:
18
- NDArray[Any]: Image with adjusted brightness
19
-
20
- >>> ## Basic tests
21
- >>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
22
- >>> brightened = brightness_image(image.astype(np.uint8), 1.5)
23
- >>> brightened.shape == image.shape
24
- True
25
-
26
- >>> img = np.full((3,3), 100, dtype=np.uint8)
27
- >>> bright = brightness_image(img, 2.0)
28
- >>> dark = brightness_image(img, 0.5)
29
- >>> bool(np.mean(bright) > np.mean(img) > np.mean(dark))
30
- True
31
-
32
- >>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
33
- >>> bright_rgb = brightness_image(rgb, 1.5)
34
- >>> bright_rgb.shape == (3,3,3)
35
- True
36
-
37
- >>> ## Test invalid inputs
38
- >>> brightness_image("not an image", 1.5)
39
- Traceback (most recent call last):
40
- ...
41
- AssertionError: Image must be a numpy array
42
-
43
- >>> brightness_image(image.astype(np.uint8), "1.5")
44
- Traceback (most recent call last):
45
- ...
46
- AssertionError: brightness_factor must be a number, got <class 'str'>
47
- """
48
- # Check input data
49
- check_image(image, ignore_dtype=ignore_dtype)
50
- assert isinstance(brightness_factor, float | int), f"brightness_factor must be a number, got {type(brightness_factor)}"
51
-
52
- # Apply brightness adjustment
53
- return cv2.convertScaleAbs(image, alpha=brightness_factor, beta=0)
54
-
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 brightness_image(image: NDArray[Any], brightness_factor: float, ignore_dtype: bool = False) -> NDArray[Any]:
11
+ """ Adjust the brightness of an image.
12
+
13
+ Args:
14
+ image (NDArray[Any]): Image to adjust brightness
15
+ brightness_factor (float): Brightness adjustment factor
16
+ ignore_dtype (bool): Ignore the dtype check
17
+ Returns:
18
+ NDArray[Any]: Image with adjusted brightness
19
+
20
+ >>> ## Basic tests
21
+ >>> image = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
22
+ >>> brightened = brightness_image(image.astype(np.uint8), 1.5)
23
+ >>> brightened.shape == image.shape
24
+ True
25
+
26
+ >>> img = np.full((3,3), 100, dtype=np.uint8)
27
+ >>> bright = brightness_image(img, 2.0)
28
+ >>> dark = brightness_image(img, 0.5)
29
+ >>> bool(np.mean(bright) > np.mean(img) > np.mean(dark))
30
+ True
31
+
32
+ >>> rgb = np.full((3,3,3), 128, dtype=np.uint8)
33
+ >>> bright_rgb = brightness_image(rgb, 1.5)
34
+ >>> bright_rgb.shape == (3,3,3)
35
+ True
36
+
37
+ >>> ## Test invalid inputs
38
+ >>> brightness_image("not an image", 1.5)
39
+ Traceback (most recent call last):
40
+ ...
41
+ AssertionError: Image must be a numpy array
42
+
43
+ >>> brightness_image(image.astype(np.uint8), "1.5")
44
+ Traceback (most recent call last):
45
+ ...
46
+ AssertionError: brightness_factor must be a number, got <class 'str'>
47
+ """
48
+ # Check input data
49
+ check_image(image, ignore_dtype=ignore_dtype)
50
+ assert isinstance(brightness_factor, float | int), f"brightness_factor must be a number, got {type(brightness_factor)}"
51
+
52
+ # Apply brightness adjustment
53
+ return cv2.convertScaleAbs(image, alpha=brightness_factor, beta=0)
54
+