11
11
Institute for Biomedical Research and Pelkmans Lab from the University of
12
12
Zurich.
13
13
"""
14
- import copy
15
14
import logging
16
15
import time
17
16
import warnings
22
21
from typing import Optional
23
22
24
23
import anndata as ad
25
- import dask
26
24
import dask .array as da
27
25
import numpy as np
28
26
import zarr
36
34
37
35
38
36
def correct (
39
- da_img ,
40
- illum_img = None ,
41
- background = 110 ,
42
- logger = None ,
37
+ img_stack : np . ndarray ,
38
+ corr_img : np . ndarray ,
39
+ background : int = 110 ,
40
+ logger : logging . Logger = None ,
43
41
):
44
42
"""
45
- Corrects single Z level input image using an illumination profile
43
+ Corrects a stack of images, using a given illumination profile (e.g. bright
44
+ in the center of the image, dim outside).
46
45
47
- The illumination profile image can be uint8 or uint16.
48
- It needs to follow the illumination profile. e.g. bright in the
49
- center of the image, dim outside
46
+ img_stack is a four-dimensional (czyx) numpy array, with dummy size along c
50
47
51
- :param img: input image to be corrected, either uint8 or uint16
52
- :type img: np.array
53
- :param illum_img: correction matrix
54
- :type illum_img: np.array
55
- :param background: value for background subtraction (optional, default 110)
56
- :type background: int
48
+ FIXME
57
49
58
50
"""
59
51
60
- # logger.info(f"Start correct function on image of shape {img.shape}")
61
-
62
- # FIXME FIXME
63
- img = da_img .compute ()
52
+ if logger is not None :
53
+ logger .debug ("Start correct, {img_stack.shape}" )
64
54
65
55
# Check shapes
66
- if illum_img .shape != img .shape [2 :]:
56
+ if corr_img .shape != img_stack .shape [2 :] or img_stack . shape [ 0 ] != 1 :
67
57
raise Exception (
68
- "Error in illumination_correction\n "
69
- f"img.shape: { img .shape } \n "
70
- f"illum_img.shape: { illum_img .shape } "
58
+ "Error in illumination_correction:\n "
59
+ f"{ img_stack .shape = } \n { corr_img .shape = } "
71
60
)
72
61
62
+ # Store info about dtype
63
+ dtype = img_stack .dtype
64
+ dtype_max = np .iinfo (dtype ).max
65
+
73
66
# Background subtraction
74
- # FIXME: is there a problem with these changes?
75
- # devdoc.net/python/dask-2.23.0-doc/delayed-best-practices.html
76
- # ?highlight=delayed#don-t-mutate-inputs
77
-
78
- below_threshold = img <= background
79
- above_threshold = np .logical_not (below_threshold )
80
- img [below_threshold ] = 0
81
- img [above_threshold ] = img [above_threshold ] - background
82
- # FIXME FIXME
83
-
84
- # Apply the illumination correction
85
- # (normalized by the max value in the illum_img)
86
- img_corr = img / (illum_img / np .max (illum_img ))[None , None , :, :]
87
-
88
- # Handle edge case: The illumination correction can increase a value
89
- # beyond the limit of the encoding, e.g. beyond 65535 for 16bit
90
- # images. This clips values that surpass this limit and triggers
91
- # a warning
92
- if np .sum (img_corr > np .iinfo (img .dtype ).max ) > 0 :
67
+ img_stack [img_stack <= background ] = 0
68
+ img_stack [img_stack > background ] -= background
69
+
70
+ # Apply the normalized correction matrix (requires a float array)
71
+ # img_stack = img_stack.astype(np.float64)
72
+ new_img_stack = img_stack / (corr_img / np .max (corr_img ))[None , None , :, :]
73
+
74
+ # Handle edge case: corrected image may have values beyond the limit of
75
+ # the encoding, e.g. beyond 65535 for 16bit images. This clips values
76
+ # that surpass this limit and triggers a warning
77
+ if np .sum (new_img_stack > dtype_max ) > 0 :
93
78
warnings .warn (
94
- f"The illumination correction created values \
95
- beyond the max range of your current image \
96
- type. These have been clipped to \
97
- { np .iinfo (img .dtype ).max } "
79
+ "Illumination correction created values beyond the max range of"
80
+ " the current image type. These have been clipped to {dtype_max=}."
98
81
)
99
- img_corr [ img_corr > np . iinfo ( img . dtype ). max ] = np . iinfo ( img . dtype ). max
82
+ new_img_stack [ new_img_stack > dtype_max ] = dtype_max
100
83
101
- # logger.info("End correct function")
84
+ if logger is not None :
85
+ logger .debug ("End correct" )
102
86
103
- # FIXME FIXME
104
- return da . array ( img_corr . astype (img . dtype ) )
87
+ # Cast back to original dtype and return
88
+ return new_img_stack . astype (dtype )
105
89
106
90
107
91
def illumination_correction (
@@ -202,11 +186,10 @@ def illumination_correction(
202
186
"correction matrix has wrong shape."
203
187
)
204
188
205
- # Load highest-resolution level from original zarr array
189
+ # Lazily load highest-res level from original zarr array
206
190
data_czyx = da .from_zarr (zarrurl + "/0" )
207
- dtype = data_czyx .dtype
208
- n_c , n_z , n_y , n_x = data_czyx .shape [:]
209
191
192
+ # Create zarr for output
210
193
new_zarr = zarr .create (
211
194
shape = data_czyx .shape ,
212
195
chunks = data_czyx .chunksize ,
@@ -216,27 +199,29 @@ def illumination_correction(
216
199
dimension_separator = "/" ,
217
200
)
218
201
202
+ # Get list of FOV-ROI regions
219
203
regions = []
220
204
for i_c , channel in enumerate (chl_list ):
221
205
for indices in list_indices :
222
206
s_z , e_z , s_y , e_y , s_x , e_x = indices [:]
223
- for i_z in range (s_z , e_z ):
224
- region = (
225
- slice (i_c , i_c + 1 ),
226
- slice (i_z , i_z + 1 ),
227
- slice (s_y , e_y ),
228
- slice (s_x , e_x ),
229
- )
230
- regions .append (region )
207
+ region = (
208
+ slice (i_c , i_c + 1 ),
209
+ slice (s_z , e_z ),
210
+ slice (s_y , e_y ),
211
+ slice (s_x , e_x ),
212
+ )
213
+ regions .append (region )
231
214
215
+ # Iterate over regions
232
216
for region in regions :
233
- corrected_img = correct (
234
- data_czyx [region ],
217
+ corrected_fov = correct (
218
+ data_czyx [region ]. compute () ,
235
219
corrections [channel ],
236
220
background = background ,
237
221
logger = logger ,
238
222
)
239
- task = corrected_img .to_zarr (
223
+
224
+ da .array (corrected_fov ).to_zarr (
240
225
url = new_zarr , region = region , compute = True , dimension_separator = "/"
241
226
)
242
227
0 commit comments