Skip to content

Commit 5b61cd9

Browse files
committed
Update illumination correction to scan ROIs sequentially - ref #75
1 parent 8763527 commit 5b61cd9

File tree

1 file changed

+50
-65
lines changed

1 file changed

+50
-65
lines changed

fractal_tasks_core/illumination_correction.py

Lines changed: 50 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
Institute for Biomedical Research and Pelkmans Lab from the University of
1212
Zurich.
1313
"""
14-
import copy
1514
import logging
1615
import time
1716
import warnings
@@ -22,7 +21,6 @@
2221
from typing import Optional
2322

2423
import anndata as ad
25-
import dask
2624
import dask.array as da
2725
import numpy as np
2826
import zarr
@@ -36,72 +34,58 @@
3634

3735

3836
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,
4341
):
4442
"""
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).
4645
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
5047
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
5749
5850
"""
5951

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}")
6454

6555
# 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:
6757
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=}"
7160
)
7261

62+
# Store info about dtype
63+
dtype = img_stack.dtype
64+
dtype_max = np.iinfo(dtype).max
65+
7366
# 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:
9378
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=}."
9881
)
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
10083

101-
# logger.info("End correct function")
84+
if logger is not None:
85+
logger.debug("End correct")
10286

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)
10589

10690

10791
def illumination_correction(
@@ -202,11 +186,10 @@ def illumination_correction(
202186
"correction matrix has wrong shape."
203187
)
204188

205-
# Load highest-resolution level from original zarr array
189+
# Lazily load highest-res level from original zarr array
206190
data_czyx = da.from_zarr(zarrurl + "/0")
207-
dtype = data_czyx.dtype
208-
n_c, n_z, n_y, n_x = data_czyx.shape[:]
209191

192+
# Create zarr for output
210193
new_zarr = zarr.create(
211194
shape=data_czyx.shape,
212195
chunks=data_czyx.chunksize,
@@ -216,27 +199,29 @@ def illumination_correction(
216199
dimension_separator="/",
217200
)
218201

202+
# Get list of FOV-ROI regions
219203
regions = []
220204
for i_c, channel in enumerate(chl_list):
221205
for indices in list_indices:
222206
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)
231214

215+
# Iterate over regions
232216
for region in regions:
233-
corrected_img = correct(
234-
data_czyx[region],
217+
corrected_fov = correct(
218+
data_czyx[region].compute(),
235219
corrections[channel],
236220
background=background,
237221
logger=logger,
238222
)
239-
task = corrected_img.to_zarr(
223+
224+
da.array(corrected_fov).to_zarr(
240225
url=new_zarr, region=region, compute=True, dimension_separator="/"
241226
)
242227

0 commit comments

Comments
 (0)