stouputils 1.10.3__tar.gz → 1.10.4__tar.gz
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-1.10.3 → stouputils-1.10.4}/PKG-INFO +1 -1
- {stouputils-1.10.3 → stouputils-1.10.4}/pyproject.toml +1 -1
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/image.py +28 -13
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/image.pyi +14 -5
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/parallel.py +7 -5
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/parallel.pyi +5 -5
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/print.py +2 -1
- {stouputils-1.10.3 → stouputils-1.10.4}/.gitignore +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/LICENSE +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/README.md +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/__init__.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/__main__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/_deprecated.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/_deprecated.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/all_doctests.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/all_doctests.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/__init__.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/automatic_docs.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/automatic_docs.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/__init__.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/config.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/config.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/image.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/image.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/video.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/applications/upscaler/video.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/archive.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/archive.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/backup.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/backup.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/collections.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/collections.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/__init__.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/cd_utils.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/cd_utils.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/github.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/github.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/pypi.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/pypi.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/pyproject.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/pyproject.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/stubs.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/continuous_delivery/stubs.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/ctx.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/ctx.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/config/get.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/config/set.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/blur.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/brightness.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/canny.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/clahe.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/common.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/contrast.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/denoise.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/invert.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/noise.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/normalize.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/resize.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/rotation.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/shearing.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/threshold.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/translation.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/zoom.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/technique.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/dataset.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/dataset_loader.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/image_loader.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/xy_tuple.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/metric_dictionnary.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/metric_utils.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/mlflow_utils.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/abstract_model.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/all.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/base_keras.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/all.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/convnext.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/densenet.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/efficientnet.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/mobilenet.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/resnet.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/squeezenet.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/vgg.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/xception.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/model_interface.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/sandbox.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/range_tuple.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/augment_dataset.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/routine.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/utils.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/decorators.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/decorators.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/__init__.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/__init__.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/common.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/common.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/downloader.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/downloader.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/linux.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/linux.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/main.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/main.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/windows.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/installer/windows.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/io.py +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/io.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/print.pyi +0 -0
- {stouputils-1.10.3 → stouputils-1.10.4}/stouputils/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stouputils
|
|
3
|
-
Version: 1.10.
|
|
3
|
+
Version: 1.10.4
|
|
4
4
|
Summary: Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Stoupy51/stouputils
|
|
6
6
|
Project-URL: Issues, https://github.com/Stoupy51/stouputils/issues
|
|
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "stouputils"
|
|
8
|
-
version = "1.10.
|
|
8
|
+
version = "1.10.4"
|
|
9
9
|
description = "Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.12"
|
|
@@ -12,7 +12,7 @@ See stouputils.data_science.data_processing for lots more image processing utili
|
|
|
12
12
|
# Imports
|
|
13
13
|
import os
|
|
14
14
|
from collections.abc import Callable
|
|
15
|
-
from typing import TYPE_CHECKING, Any, cast
|
|
15
|
+
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
16
16
|
|
|
17
17
|
from .io import super_open
|
|
18
18
|
from .print import debug, info
|
|
@@ -22,14 +22,15 @@ if TYPE_CHECKING:
|
|
|
22
22
|
from numpy.typing import NDArray
|
|
23
23
|
from PIL import Image
|
|
24
24
|
|
|
25
|
+
PIL_Image_or_NDArray = TypeVar("PIL_Image_or_NDArray", bound="Image.Image | NDArray[np.number]")
|
|
25
26
|
|
|
26
27
|
# Functions
|
|
27
28
|
def image_resize(
|
|
28
|
-
image:
|
|
29
|
+
image: PIL_Image_or_NDArray,
|
|
29
30
|
max_result_size: int,
|
|
30
31
|
resampling: "Image.Resampling | None" = None,
|
|
31
32
|
min_or_max: Callable[[int, int], int] = max,
|
|
32
|
-
return_type: type[
|
|
33
|
+
return_type: type[PIL_Image_or_NDArray] | str = "same",
|
|
33
34
|
keep_aspect_ratio: bool = True,
|
|
34
35
|
) -> Any:
|
|
35
36
|
""" Resize an image while preserving its aspect ratio by default.
|
|
@@ -114,17 +115,17 @@ def image_resize(
|
|
|
114
115
|
return new_image
|
|
115
116
|
else:
|
|
116
117
|
return np.array(new_image)
|
|
117
|
-
elif return_type
|
|
118
|
+
elif return_type != Image.Image:
|
|
118
119
|
return np.array(new_image)
|
|
119
120
|
else:
|
|
120
121
|
return new_image
|
|
121
122
|
|
|
122
123
|
|
|
123
124
|
def auto_crop(
|
|
124
|
-
image:
|
|
125
|
+
image: PIL_Image_or_NDArray,
|
|
125
126
|
mask: "NDArray[np.bool_] | None" = None,
|
|
126
127
|
threshold: int | float | Callable[["NDArray[np.number]"], int | float] | None = None,
|
|
127
|
-
return_type: type[
|
|
128
|
+
return_type: type[PIL_Image_or_NDArray] | str = "same",
|
|
128
129
|
contiguous: bool = True,
|
|
129
130
|
) -> Any:
|
|
130
131
|
""" Automatically crop an image to remove zero or uniform regions.
|
|
@@ -231,7 +232,7 @@ def auto_crop(
|
|
|
231
232
|
|
|
232
233
|
# Return original if no content found
|
|
233
234
|
if not (np.any(rows_with_content) and np.any(cols_with_content)):
|
|
234
|
-
return image_array if return_type
|
|
235
|
+
return image_array if return_type != Image.Image else (image if original_was_pil else Image.fromarray(image_array))
|
|
235
236
|
|
|
236
237
|
# Crop based on contiguous parameter
|
|
237
238
|
if contiguous:
|
|
@@ -257,7 +258,7 @@ def auto_crop(
|
|
|
257
258
|
# Return in requested format
|
|
258
259
|
if return_type == "same":
|
|
259
260
|
return Image.fromarray(cropped_array) if original_was_pil else cropped_array
|
|
260
|
-
return cropped_array if return_type
|
|
261
|
+
return cropped_array if return_type != Image.Image else Image.fromarray(cropped_array)
|
|
261
262
|
|
|
262
263
|
|
|
263
264
|
def numpy_to_gif(
|
|
@@ -268,11 +269,13 @@ def numpy_to_gif(
|
|
|
268
269
|
mkdir: bool = True,
|
|
269
270
|
**kwargs: Any
|
|
270
271
|
) -> None:
|
|
271
|
-
""" Generate a '.gif' file from a numpy array for 3D visualization.
|
|
272
|
+
""" Generate a '.gif' file from a numpy array for 3D/4D visualization.
|
|
272
273
|
|
|
273
274
|
Args:
|
|
274
275
|
path (str): Path to the output .gif file.
|
|
275
|
-
array (NDArray): Numpy array to be dumped (must be 3D
|
|
276
|
+
array (NDArray): Numpy array to be dumped (must be 3D or 4D).
|
|
277
|
+
3D: (depth, height, width) - e.g. (64, 1024, 1024)
|
|
278
|
+
4D: (depth, height, width, channels) - e.g. (50, 64, 1024, 3)
|
|
276
279
|
duration (int): Duration between frames in milliseconds.
|
|
277
280
|
loop (int): Number of loops (0 = infinite).
|
|
278
281
|
mkdir (bool): Create the directory if it does not exist.
|
|
@@ -282,9 +285,14 @@ def numpy_to_gif(
|
|
|
282
285
|
|
|
283
286
|
.. code-block:: python
|
|
284
287
|
|
|
288
|
+
> # 3D array example
|
|
285
289
|
> array = np.random.randint(0, 256, (10, 100, 100), dtype=np.uint8)
|
|
286
290
|
> numpy_to_gif("output_10_frames_100x100.gif", array, duration=200, loop=0)
|
|
287
291
|
|
|
292
|
+
> # 4D array example (batch of 3D images)
|
|
293
|
+
> array_4d = np.random.randint(0, 256, (5, 10, 100, 3), dtype=np.uint8)
|
|
294
|
+
> numpy_to_gif("output_50_frames_100x100.gif", array_4d, duration=200)
|
|
295
|
+
|
|
288
296
|
> total_duration = 1000 # 1 second
|
|
289
297
|
> numpy_to_gif("output_1s.gif", array, duration=total_duration // len(array))
|
|
290
298
|
"""
|
|
@@ -293,11 +301,15 @@ def numpy_to_gif(
|
|
|
293
301
|
from PIL import Image
|
|
294
302
|
|
|
295
303
|
# Assertions
|
|
296
|
-
assert array.ndim
|
|
304
|
+
assert array.ndim in (3, 4), f"The input array must be 3D or 4D, got shape {array.shape} instead."
|
|
305
|
+
if array.ndim == 4:
|
|
306
|
+
assert array.shape[-1] in (1, 3), f"For 4D arrays, the last dimension must be 1 or 3 (channels), got shape {array.shape} instead."
|
|
297
307
|
|
|
298
308
|
# Create directory if needed
|
|
299
309
|
if mkdir:
|
|
300
|
-
os.
|
|
310
|
+
dirname: str = os.path.dirname(path)
|
|
311
|
+
if dirname != "":
|
|
312
|
+
os.makedirs(dirname, exist_ok=True)
|
|
301
313
|
|
|
302
314
|
# Normalize array if outside [0-255] range to [0-1]
|
|
303
315
|
array = array.astype(np.float32)
|
|
@@ -308,7 +320,10 @@ def numpy_to_gif(
|
|
|
308
320
|
# Scale to [0-255] if in [0-1] range
|
|
309
321
|
mini, maxi = np.min(array), np.max(array)
|
|
310
322
|
if mini >= 0.0 and maxi <= 1.0:
|
|
311
|
-
array = (array * 255)
|
|
323
|
+
array = (array * 255)
|
|
324
|
+
|
|
325
|
+
# Ensure array is uint8 for PIL compatibility
|
|
326
|
+
array = array.astype(np.uint8)
|
|
312
327
|
|
|
313
328
|
# Convert each slice to PIL Image
|
|
314
329
|
pil_images: list[Image.Image] = [
|
|
@@ -4,9 +4,11 @@ from .print import debug as debug, info as info
|
|
|
4
4
|
from PIL import Image
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from numpy.typing import NDArray
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, TypeVar
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
PIL_Image_or_NDArray = TypeVar('PIL_Image_or_NDArray', bound='Image.Image | NDArray[np.number]')
|
|
10
|
+
|
|
11
|
+
def image_resize(image: PIL_Image_or_NDArray, max_result_size: int, resampling: Image.Resampling | None = None, min_or_max: Callable[[int, int], int] = ..., return_type: type[PIL_Image_or_NDArray] | str = 'same', keep_aspect_ratio: bool = True) -> Any:
|
|
10
12
|
''' Resize an image while preserving its aspect ratio by default.
|
|
11
13
|
\tScales the image so that its largest dimension equals max_result_size.
|
|
12
14
|
|
|
@@ -45,7 +47,7 @@ def image_resize(image: Image.Image | NDArray[np.number], max_result_size: int,
|
|
|
45
47
|
\t\t>>> image_resize(pil_image, 50, resampling=Image.Resampling.NEAREST).size
|
|
46
48
|
\t\t(50, 25)
|
|
47
49
|
\t'''
|
|
48
|
-
def auto_crop(image:
|
|
50
|
+
def auto_crop(image: PIL_Image_or_NDArray, mask: NDArray[np.bool_] | None = None, threshold: int | float | Callable[[NDArray[np.number]], int | float] | None = None, return_type: type[PIL_Image_or_NDArray] | str = 'same', contiguous: bool = True) -> Any:
|
|
49
51
|
''' Automatically crop an image to remove zero or uniform regions.
|
|
50
52
|
|
|
51
53
|
\tThis function crops the image to keep only the region where pixels are non-zero
|
|
@@ -120,11 +122,13 @@ def auto_crop(image: Image.Image | NDArray[np.number], mask: NDArray[np.bool_] |
|
|
|
120
122
|
\t(30, 30, 6)
|
|
121
123
|
\t'''
|
|
122
124
|
def numpy_to_gif(path: str, array: NDArray[np.integer | np.floating | np.bool_], duration: int = 100, loop: int = 0, mkdir: bool = True, **kwargs: Any) -> None:
|
|
123
|
-
''' Generate a \'.gif\' file from a numpy array for 3D visualization.
|
|
125
|
+
''' Generate a \'.gif\' file from a numpy array for 3D/4D visualization.
|
|
124
126
|
|
|
125
127
|
\tArgs:
|
|
126
128
|
\t\tpath (str): Path to the output .gif file.
|
|
127
|
-
\t\tarray (NDArray): Numpy array to be dumped (must be 3D
|
|
129
|
+
\t\tarray (NDArray): Numpy array to be dumped (must be 3D or 4D).
|
|
130
|
+
\t\t\t3D: (depth, height, width) - e.g. (64, 1024, 1024)
|
|
131
|
+
\t\t\t4D: (depth, height, width, channels) - e.g. (50, 64, 1024, 3)
|
|
128
132
|
\t\tduration (int): Duration between frames in milliseconds.
|
|
129
133
|
\t\tloop (int): Number of loops (0 = infinite).
|
|
130
134
|
\t\tmkdir (bool): Create the directory if it does not exist.
|
|
@@ -134,9 +138,14 @@ def numpy_to_gif(path: str, array: NDArray[np.integer | np.floating | np.bool_],
|
|
|
134
138
|
|
|
135
139
|
\t\t.. code-block:: python
|
|
136
140
|
|
|
141
|
+
\t\t\t> # 3D array example
|
|
137
142
|
\t\t\t> array = np.random.randint(0, 256, (10, 100, 100), dtype=np.uint8)
|
|
138
143
|
\t\t\t> numpy_to_gif("output_10_frames_100x100.gif", array, duration=200, loop=0)
|
|
139
144
|
|
|
145
|
+
\t\t\t> # 4D array example (batch of 3D images)
|
|
146
|
+
\t\t\t> array_4d = np.random.randint(0, 256, (5, 10, 100, 3), dtype=np.uint8)
|
|
147
|
+
\t\t\t> numpy_to_gif("output_50_frames_100x100.gif", array_4d, duration=200)
|
|
148
|
+
|
|
140
149
|
\t\t\t> total_duration = 1000 # 1 second
|
|
141
150
|
\t\t\t> numpy_to_gif("output_1s.gif", array, duration=total_duration // len(array))
|
|
142
151
|
\t'''
|
|
@@ -14,7 +14,7 @@ I highly encourage you to read the function docstrings to understand when to use
|
|
|
14
14
|
# Imports
|
|
15
15
|
import os
|
|
16
16
|
import time
|
|
17
|
-
from collections.abc import Callable
|
|
17
|
+
from collections.abc import Callable, Iterable
|
|
18
18
|
from typing import Any, TypeVar, cast
|
|
19
19
|
|
|
20
20
|
from .ctx import SetMPStartMethod
|
|
@@ -36,7 +36,7 @@ R = TypeVar("R")
|
|
|
36
36
|
# Functions
|
|
37
37
|
def multiprocessing(
|
|
38
38
|
func: Callable[..., R] | list[Callable[..., R]],
|
|
39
|
-
args:
|
|
39
|
+
args: Iterable[T],
|
|
40
40
|
use_starmap: bool = False,
|
|
41
41
|
chunksize: int = 1,
|
|
42
42
|
desc: str = "",
|
|
@@ -54,7 +54,7 @@ def multiprocessing(
|
|
|
54
54
|
|
|
55
55
|
Args:
|
|
56
56
|
func (Callable | list[Callable]): Function to execute, or list of functions (one per argument)
|
|
57
|
-
args (
|
|
57
|
+
args (Iterable): Iterable of arguments to pass to the function(s)
|
|
58
58
|
use_starmap (bool): Whether to use starmap or not (Defaults to False):
|
|
59
59
|
True means the function will be called like func(\*args[i]) instead of func(args[i])
|
|
60
60
|
chunksize (int): Number of arguments to process at a time
|
|
@@ -109,6 +109,7 @@ def multiprocessing(
|
|
|
109
109
|
from tqdm.contrib.concurrent import process_map # pyright: ignore[reportUnknownVariableType]
|
|
110
110
|
|
|
111
111
|
# Handle parameters
|
|
112
|
+
args = list(args) # Ensure we have a list (not other iterable)
|
|
112
113
|
if max_workers == -1:
|
|
113
114
|
max_workers = CPU_COUNT
|
|
114
115
|
if isinstance(max_workers, float):
|
|
@@ -154,7 +155,7 @@ def multiprocessing(
|
|
|
154
155
|
|
|
155
156
|
def multithreading(
|
|
156
157
|
func: Callable[..., R] | list[Callable[..., R]],
|
|
157
|
-
args:
|
|
158
|
+
args: Iterable[T],
|
|
158
159
|
use_starmap: bool = False,
|
|
159
160
|
desc: str = "",
|
|
160
161
|
max_workers: int | float = CPU_COUNT,
|
|
@@ -171,7 +172,7 @@ def multithreading(
|
|
|
171
172
|
|
|
172
173
|
Args:
|
|
173
174
|
func (Callable | list[Callable]): Function to execute, or list of functions (one per argument)
|
|
174
|
-
args (
|
|
175
|
+
args (Iterable): Iterable of arguments to pass to the function(s)
|
|
175
176
|
use_starmap (bool): Whether to use starmap or not (Defaults to False):
|
|
176
177
|
True means the function will be called like func(\*args[i]) instead of func(args[i])
|
|
177
178
|
desc (str): Description displayed in the progress bar
|
|
@@ -222,6 +223,7 @@ def multithreading(
|
|
|
222
223
|
from tqdm.auto import tqdm
|
|
223
224
|
|
|
224
225
|
# Handle parameters
|
|
226
|
+
args = list(args) # Ensure we have a list (not other iterable)
|
|
225
227
|
if max_workers == -1:
|
|
226
228
|
max_workers = CPU_COUNT
|
|
227
229
|
if isinstance(max_workers, float):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .ctx import SetMPStartMethod as SetMPStartMethod
|
|
2
2
|
from .print import BAR_FORMAT as BAR_FORMAT, MAGENTA as MAGENTA
|
|
3
|
-
from collections.abc import Callable
|
|
3
|
+
from collections.abc import Callable, Iterable
|
|
4
4
|
from typing import Any, TypeVar
|
|
5
5
|
|
|
6
6
|
def doctest_square(x: int) -> int: ...
|
|
@@ -10,7 +10,7 @@ CPU_COUNT: int
|
|
|
10
10
|
T = TypeVar('T')
|
|
11
11
|
R = TypeVar('R')
|
|
12
12
|
|
|
13
|
-
def multiprocessing(func: Callable[..., R] | list[Callable[..., R]], args:
|
|
13
|
+
def multiprocessing(func: Callable[..., R] | list[Callable[..., R]], args: Iterable[T], use_starmap: bool = False, chunksize: int = 1, desc: str = '', max_workers: int | float = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
|
|
14
14
|
''' Method to execute a function in parallel using multiprocessing
|
|
15
15
|
|
|
16
16
|
\t- For CPU-bound operations where the GIL (Global Interpreter Lock) is a bottleneck.
|
|
@@ -19,7 +19,7 @@ def multiprocessing(func: Callable[..., R] | list[Callable[..., R]], args: list[
|
|
|
19
19
|
|
|
20
20
|
\tArgs:
|
|
21
21
|
\t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
|
|
22
|
-
\t\targs\t\t\t\t(
|
|
22
|
+
\t\targs\t\t\t\t(Iterable):\t\t\tIterable of arguments to pass to the function(s)
|
|
23
23
|
\t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
|
|
24
24
|
\t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
|
|
25
25
|
\t\tchunksize\t\t\t(int):\t\t\t\tNumber of arguments to process at a time
|
|
@@ -66,7 +66,7 @@ def multiprocessing(func: Callable[..., R] | list[Callable[..., R]], args: list[
|
|
|
66
66
|
\t\t\t. )
|
|
67
67
|
\t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
68
68
|
\t'''
|
|
69
|
-
def multithreading(func: Callable[..., R] | list[Callable[..., R]], args:
|
|
69
|
+
def multithreading(func: Callable[..., R] | list[Callable[..., R]], args: Iterable[T], use_starmap: bool = False, desc: str = '', max_workers: int | float = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
|
|
70
70
|
''' Method to execute a function in parallel using multithreading, you should use it:
|
|
71
71
|
|
|
72
72
|
\t- For I/O-bound operations where the GIL is not a bottleneck, such as network requests or disk operations.
|
|
@@ -75,7 +75,7 @@ def multithreading(func: Callable[..., R] | list[Callable[..., R]], args: list[T
|
|
|
75
75
|
|
|
76
76
|
\tArgs:
|
|
77
77
|
\t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
|
|
78
|
-
\t\targs\t\t\t\t(
|
|
78
|
+
\t\targs\t\t\t\t(Iterable):\t\t\tIterable of arguments to pass to the function(s)
|
|
79
79
|
\t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
|
|
80
80
|
\t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
|
|
81
81
|
\t\tdesc\t\t\t\t(str):\t\t\t\tDescription displayed in the progress bar
|
|
@@ -470,7 +470,8 @@ def show_version(main_package: str = "stouputils", primary_color: str = CYAN, se
|
|
|
470
470
|
|
|
471
471
|
# Get Python version
|
|
472
472
|
python_version: str = f" Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} "
|
|
473
|
-
|
|
473
|
+
minimum_separator_length: int = len(python_version) + 10 # Always at least 5 dashes on each side
|
|
474
|
+
separator_length: int = max(minimum_separator_length, longest_name_length + longest_version_length + 4)
|
|
474
475
|
python_text_length: int = len(python_version)
|
|
475
476
|
left_dashes: int = (separator_length - python_text_length) // 2
|
|
476
477
|
right_dashes: int = separator_length - python_text_length - left_dashes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/axis_flip.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/blur.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/brightness.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/canny.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/clahe.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/common.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/contrast.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/denoise.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/invert.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/laplacian.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/median_blur.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/noise.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/normalize.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/resize.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/rotation.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/salt_pepper.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/sharpening.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/shearing.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/threshold.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/translation.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image/zoom.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/image_preprocess.py
RENAMED
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/data_processing/technique.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/dataset/grouping_strategy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras/efficientnet.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/models/keras_utils/visualizations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/exhaustive_process.py
RENAMED
|
File without changes
|
{stouputils-1.10.3 → stouputils-1.10.4}/stouputils/data_science/scripts/preprocess_dataset.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|