napari-tmidas 0.3.3__py3-none-any.whl → 0.3.4__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.
- napari_tmidas/_tests/test_skimage_filters.py +19 -0
- napari_tmidas/_version.py +2 -2
- napari_tmidas/processing_functions/skimage_filters.py +49 -23
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/METADATA +1 -1
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/RECORD +9 -9
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/WHEEL +0 -0
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/entry_points.txt +0 -0
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {napari_tmidas-0.3.3.dist-info → napari_tmidas-0.3.4.dist-info}/top_level.txt +0 -0
|
@@ -257,3 +257,22 @@ class TestCLAHE:
|
|
|
257
257
|
assert result_float32.dtype == np.float32
|
|
258
258
|
assert result_float32.max() <= 1.0
|
|
259
259
|
assert result_float32.min() >= 0.0
|
|
260
|
+
|
|
261
|
+
def test_clahe_max_workers_parameter(self):
|
|
262
|
+
"""Test that max_workers parameter is respected"""
|
|
263
|
+
# Create a 4D image that will trigger parallel processing
|
|
264
|
+
image_4d = np.random.rand(10, 50, 100, 100) * 0.5
|
|
265
|
+
|
|
266
|
+
# Test with different worker counts
|
|
267
|
+
result_1 = equalize_histogram(image_4d, max_workers=1)
|
|
268
|
+
result_4 = equalize_histogram(image_4d, max_workers=4)
|
|
269
|
+
result_8 = equalize_histogram(image_4d, max_workers=8)
|
|
270
|
+
|
|
271
|
+
# All should produce same shape
|
|
272
|
+
assert result_1.shape == image_4d.shape
|
|
273
|
+
assert result_4.shape == image_4d.shape
|
|
274
|
+
assert result_8.shape == image_4d.shape
|
|
275
|
+
|
|
276
|
+
# Results should be nearly identical (some floating point differences are OK)
|
|
277
|
+
np.testing.assert_allclose(result_1, result_4, rtol=1e-5)
|
|
278
|
+
np.testing.assert_allclose(result_1, result_8, rtol=1e-5)
|
napari_tmidas/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.4'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 4)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
Processing functions that depend on scikit-image.
|
|
4
4
|
"""
|
|
5
5
|
import concurrent.futures
|
|
6
|
-
import os
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
|
|
@@ -49,10 +48,18 @@ if SKIMAGE_AVAILABLE:
|
|
|
49
48
|
"default": 0,
|
|
50
49
|
"description": "Size of the local region (0 = auto-calculate based on image size). For small features use smaller values (e.g., 32), for large features use larger values (e.g., 128)",
|
|
51
50
|
},
|
|
51
|
+
"max_workers": {
|
|
52
|
+
"type": int,
|
|
53
|
+
"default": 4,
|
|
54
|
+
"description": "Maximum number of parallel workers (default: 4). Lower values use less memory but are slower. Range: 1-16",
|
|
55
|
+
},
|
|
52
56
|
},
|
|
53
57
|
)
|
|
54
58
|
def equalize_histogram(
|
|
55
|
-
image: np.ndarray,
|
|
59
|
+
image: np.ndarray,
|
|
60
|
+
clip_limit: float = 0.01,
|
|
61
|
+
kernel_size: int = 0,
|
|
62
|
+
max_workers: int = 4,
|
|
56
63
|
) -> np.ndarray:
|
|
57
64
|
"""
|
|
58
65
|
Apply CLAHE (Contrast Limited Adaptive Histogram Equalization) to enhance local contrast.
|
|
@@ -70,23 +77,29 @@ if SKIMAGE_AVAILABLE:
|
|
|
70
77
|
Higher values give more contrast but may amplify noise
|
|
71
78
|
kernel_size : int
|
|
72
79
|
Size of the contextual regions (0 = auto-calculate based on image size)
|
|
80
|
+
max_workers : int
|
|
81
|
+
Maximum number of parallel workers for processing large datasets (default: 4)
|
|
82
|
+
Lower values reduce memory usage, higher values increase speed
|
|
73
83
|
|
|
74
84
|
Returns
|
|
75
85
|
-------
|
|
76
86
|
np.ndarray
|
|
77
87
|
CLAHE-enhanced image with same dtype as input
|
|
78
|
-
|
|
88
|
+
|
|
79
89
|
Notes
|
|
80
90
|
-----
|
|
81
91
|
For large multi-dimensional datasets (TZYX), processing is parallelized across
|
|
82
|
-
the first dimension to utilize multiple CPU cores effectively.
|
|
92
|
+
the first dimension to utilize multiple CPU cores effectively. The max_workers
|
|
93
|
+
parameter controls memory usage vs speed tradeoff.
|
|
83
94
|
"""
|
|
84
95
|
# Store original dtype to convert back later
|
|
85
96
|
original_dtype = image.dtype
|
|
86
|
-
|
|
97
|
+
|
|
87
98
|
# Print diagnostic info for multi-dimensional data
|
|
88
99
|
if image.ndim > 2:
|
|
89
|
-
print(
|
|
100
|
+
print(
|
|
101
|
+
f"Applying CLAHE to {image.ndim}D image with shape {image.shape}"
|
|
102
|
+
)
|
|
90
103
|
|
|
91
104
|
# Auto-calculate kernel size if not specified
|
|
92
105
|
if kernel_size <= 0:
|
|
@@ -99,14 +112,19 @@ if SKIMAGE_AVAILABLE:
|
|
|
99
112
|
# Ensure kernel_size is odd
|
|
100
113
|
if kernel_size % 2 == 0:
|
|
101
114
|
kernel_size += 1
|
|
102
|
-
|
|
115
|
+
|
|
103
116
|
if image.ndim > 2:
|
|
104
117
|
print(f"Using kernel_size={kernel_size}, clip_limit={clip_limit}")
|
|
105
|
-
|
|
118
|
+
|
|
119
|
+
# Clamp max_workers to reasonable range
|
|
120
|
+
max_workers = max(1, min(max_workers, 16))
|
|
121
|
+
|
|
106
122
|
# For 4D data (TZYX), parallelize across first dimension for better performance
|
|
107
123
|
if image.ndim == 4 and image.shape[0] > 1:
|
|
108
|
-
print(
|
|
109
|
-
|
|
124
|
+
print(
|
|
125
|
+
f"Parallelizing CLAHE across {image.shape[0]} timepoints/slices using {max_workers} workers..."
|
|
126
|
+
)
|
|
127
|
+
|
|
110
128
|
def process_slice(idx):
|
|
111
129
|
"""Process a single slice along first dimension"""
|
|
112
130
|
result_slice = skimage.exposure.equalize_adapthist(
|
|
@@ -115,21 +133,26 @@ if SKIMAGE_AVAILABLE:
|
|
|
115
133
|
if (idx + 1) % max(1, image.shape[0] // 10) == 0:
|
|
116
134
|
print(f" Processed {idx + 1}/{image.shape[0]} slices")
|
|
117
135
|
return result_slice
|
|
118
|
-
|
|
119
|
-
# Process in parallel
|
|
136
|
+
|
|
137
|
+
# Process in parallel with limited workers to control memory usage
|
|
120
138
|
with concurrent.futures.ThreadPoolExecutor(
|
|
121
|
-
max_workers=
|
|
139
|
+
max_workers=max_workers
|
|
122
140
|
) as executor:
|
|
123
|
-
futures = [
|
|
141
|
+
futures = [
|
|
142
|
+
executor.submit(process_slice, i)
|
|
143
|
+
for i in range(image.shape[0])
|
|
144
|
+
]
|
|
124
145
|
results = [future.result() for future in futures]
|
|
125
|
-
|
|
146
|
+
|
|
126
147
|
result = np.stack(results, axis=0)
|
|
127
148
|
print("CLAHE processing complete!")
|
|
128
|
-
|
|
149
|
+
|
|
129
150
|
elif image.ndim == 3 and image.shape[0] > 5:
|
|
130
151
|
# For 3D data with many slices, also parallelize
|
|
131
|
-
print(
|
|
132
|
-
|
|
152
|
+
print(
|
|
153
|
+
f"Parallelizing CLAHE across {image.shape[0]} slices using {max_workers} workers..."
|
|
154
|
+
)
|
|
155
|
+
|
|
133
156
|
def process_slice(idx):
|
|
134
157
|
"""Process a single 2D slice"""
|
|
135
158
|
result_slice = skimage.exposure.equalize_adapthist(
|
|
@@ -138,14 +161,17 @@ if SKIMAGE_AVAILABLE:
|
|
|
138
161
|
if (idx + 1) % max(1, image.shape[0] // 10) == 0:
|
|
139
162
|
print(f" Processed {idx + 1}/{image.shape[0]} slices")
|
|
140
163
|
return result_slice
|
|
141
|
-
|
|
142
|
-
# Process in parallel
|
|
164
|
+
|
|
165
|
+
# Process in parallel with limited workers to control memory usage
|
|
143
166
|
with concurrent.futures.ThreadPoolExecutor(
|
|
144
|
-
max_workers=
|
|
167
|
+
max_workers=max_workers
|
|
145
168
|
) as executor:
|
|
146
|
-
futures = [
|
|
169
|
+
futures = [
|
|
170
|
+
executor.submit(process_slice, i)
|
|
171
|
+
for i in range(image.shape[0])
|
|
172
|
+
]
|
|
147
173
|
results = [future.result() for future in futures]
|
|
148
|
-
|
|
174
|
+
|
|
149
175
|
result = np.stack(results, axis=0)
|
|
150
176
|
print("CLAHE processing complete!")
|
|
151
177
|
else:
|
|
@@ -10,7 +10,7 @@ napari_tmidas/_registry.py,sha256=yunbEoDe1JZREMab4BeP7wka17IwK1toV5g1imju30c,21
|
|
|
10
10
|
napari_tmidas/_roi_colocalization.py,sha256=0ZSs7JlJKPhGibnETf6Rj746T3YV4AUgynWmZbmNjHw,92257
|
|
11
11
|
napari_tmidas/_sample_data.py,sha256=khuv1jemz_fCjqNwEKMFf83Ju0EN4S89IKydsUMmUxw,645
|
|
12
12
|
napari_tmidas/_ui_utils.py,sha256=wBmaR-3wdgizb234atsjUU2DElsM5-tf4TIsxGLaHzI,1499
|
|
13
|
-
napari_tmidas/_version.py,sha256=
|
|
13
|
+
napari_tmidas/_version.py,sha256=3nDaC5e0d_scBB1bUEKPlItbvbY0PmXNNyyOTNFNWNI,704
|
|
14
14
|
napari_tmidas/_widget.py,sha256=Uab5WuJK2fgdlGga6iNnHsiZjRMUq2KM3u0N5JJW8DA,5495
|
|
15
15
|
napari_tmidas/_writer.py,sha256=wbVfHFjjHdybSg37VR4lVmL-kdCkDZsUPDJ66AVLaFQ,1941
|
|
16
16
|
napari_tmidas/napari.yaml,sha256=1Am1dA0-ZtCXk6veIT6jrMz3zwQ7dF8_p9tZTFx_vTg,2641
|
|
@@ -28,7 +28,7 @@ napari_tmidas/_tests/test_regionprops_analysis.py,sha256=IGAEtdg83R9aH8wsINR8VCv
|
|
|
28
28
|
napari_tmidas/_tests/test_registry.py,sha256=0dVpeGE273YDPDy6KMInfkz2JAaJ_SUKFOySKn160_c,4795
|
|
29
29
|
napari_tmidas/_tests/test_sample_data.py,sha256=D1HU_C3hWpO3mlSW_7Z94xaYHDtxz0XUrMjQoYop9Ag,104
|
|
30
30
|
napari_tmidas/_tests/test_scipy_filters.py,sha256=SUcgyFh2IY4YVJvVO6_J1JdgkCsYdW36RgpHLkkp2vg,6268
|
|
31
|
-
napari_tmidas/_tests/test_skimage_filters.py,sha256=
|
|
31
|
+
napari_tmidas/_tests/test_skimage_filters.py,sha256=yj0DrfOYyyyjNps3Yzvwwh_wtR4Mmz4_L5DNjFNBbSs,10739
|
|
32
32
|
napari_tmidas/_tests/test_split_channels.py,sha256=aMvjppoHlPAuwWLGYa1UcfBM_fvu0zM7Elam5JWaAQw,7448
|
|
33
33
|
napari_tmidas/_tests/test_spotiflow.py,sha256=BLSaD8z8r2zbkYEGmfQ3JkSgw5OkvEORnSzpbkIIz4Y,2578
|
|
34
34
|
napari_tmidas/_tests/test_tyx_display_fix.py,sha256=rhKbmM1rkPAAUeV3x3VuJkzXwEoqgi3Gtrxi1PP4ijs,4804
|
|
@@ -51,16 +51,16 @@ napari_tmidas/processing_functions/regionprops_analysis.py,sha256=ySmzlY_F8uXWQI
|
|
|
51
51
|
napari_tmidas/processing_functions/sam2_env_manager.py,sha256=w-X493XdHWAE8UhyHhEEVJ3uvLi2VdS-UFU7yPqnagg,2569
|
|
52
52
|
napari_tmidas/processing_functions/sam2_mp4.py,sha256=lEdrqQP36_kw2g3soyu81CCRXCkI5DdSExfq5Bc5kig,11523
|
|
53
53
|
napari_tmidas/processing_functions/scipy_filters.py,sha256=1Y69F5Pe-MEJPwQEs_6Ci3ncFuTKiRAuKRvDxmOQUPw,17871
|
|
54
|
-
napari_tmidas/processing_functions/skimage_filters.py,sha256=
|
|
54
|
+
napari_tmidas/processing_functions/skimage_filters.py,sha256=dLEKw8Nw9-9b6hbPLebifmYj6l5x7KeA28DthWaMBP0,28920
|
|
55
55
|
napari_tmidas/processing_functions/spotiflow_detection.py,sha256=2FLnDNXLc0eNj8vhp_XBv_bukX5pJOEhuiyXbUzzcyU,32811
|
|
56
56
|
napari_tmidas/processing_functions/spotiflow_env_manager.py,sha256=07J_tYADMvIVIr_afniSNt8uEduecqpNblSWEj9aH7Q,20323
|
|
57
57
|
napari_tmidas/processing_functions/timepoint_merger.py,sha256=7pXyfcI2rXZz6_TP3v_WejmMFivNVyUzkzBmifMiFKA,27424
|
|
58
58
|
napari_tmidas/processing_functions/trackastra_tracking.py,sha256=IkFk5HoEZmKdcu5jXri4WMhHN1KTADDMxSpeYfPgSbo,9976
|
|
59
59
|
napari_tmidas/processing_functions/viscy_env_manager.py,sha256=eJ9NsyrtypvxRAFVir9n9RtKaaj6GTpIrOFNLScoVDY,11999
|
|
60
60
|
napari_tmidas/processing_functions/viscy_virtual_staining.py,sha256=Aa__YweYzSFYUTkbneDZ2lxRBplozrQvXGSiMFzUhA4,12422
|
|
61
|
-
napari_tmidas-0.3.
|
|
62
|
-
napari_tmidas-0.3.
|
|
63
|
-
napari_tmidas-0.3.
|
|
64
|
-
napari_tmidas-0.3.
|
|
65
|
-
napari_tmidas-0.3.
|
|
66
|
-
napari_tmidas-0.3.
|
|
61
|
+
napari_tmidas-0.3.4.dist-info/licenses/LICENSE,sha256=tSjiOqj57exmEIfP2YVPCEeQf0cH49S6HheQR8IiY3g,1485
|
|
62
|
+
napari_tmidas-0.3.4.dist-info/METADATA,sha256=1ZH0yNnlUxykDRyQ_QgVkUF4i_qIQ-REnJDnpV1tCX8,10348
|
|
63
|
+
napari_tmidas-0.3.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
64
|
+
napari_tmidas-0.3.4.dist-info/entry_points.txt,sha256=fbVjzbJTm4aDMIBtel1Lyqvq-CwXY7wmCOo_zJ-jtRY,60
|
|
65
|
+
napari_tmidas-0.3.4.dist-info/top_level.txt,sha256=63ybdxCZ4SeT13f_Ou4TsivGV_2Gtm_pJOXToAt30_E,14
|
|
66
|
+
napari_tmidas-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|