Skip to content

Commit 77d70dd

Browse files
committed
feat: in progress with ome tiff to precomputed
1 parent de5bb05 commit 77d70dd

File tree

1 file changed

+122
-96
lines changed

1 file changed

+122
-96
lines changed

examples/load_tiff.py

Lines changed: 122 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,137 @@
1-
import argparse
1+
# %% Import packages
2+
23
import itertools
3-
import webbrowser
4-
import neuroglancer
5-
import neuroglancer.cli
64
from pathlib import Path
75
from bfio import BioReader
8-
import dask
9-
import dask.array
106
import numpy as np
7+
from cloudvolume import CloudVolume
8+
from cloudvolume.lib import touch
9+
import json
10+
11+
# %% Define the path to the files
1112

1213
HERE = Path(__file__).parent
1314

14-
FILEPATH = Path("x.ome.tiff")
15-
16-
17-
def add_image_layer(state, path, name="image"):
18-
br = BioReader(str(path), backend="bioformats")
19-
chunk_shape = np.array([256, 256, 128, 1])
20-
shape = np.array(br.shape)
21-
num_chunks_per_dim = np.ceil(shape / chunk_shape).astype(int)
22-
padded_chunk_shape = num_chunks_per_dim * chunk_shape
23-
24-
def chunked_reader(x_i, y_i, z_i, c):
25-
x_start, x_end = x_i * chunk_shape[0], min((x_i + 1) * chunk_shape[0], shape[0])
26-
y_start, y_end = y_i * chunk_shape[1], min((y_i + 1) * chunk_shape[1], shape[1])
27-
z_start, z_end = z_i * chunk_shape[2], min((z_i + 1) * chunk_shape[2], shape[2])
28-
29-
# Read the chunk from the BioReader
30-
chunk = br.read(
31-
X=(x_start, x_end), Y=(y_start, y_end), Z=(z_start, z_end), C=(c,)
32-
)
33-
# Extend the chunk to be X, Y, Z, 1 not just X, Y, Z
34-
chunk = np.expand_dims(chunk, axis=-1)
35-
# If the chunk is smaller than the padded chunk shape, pad it
36-
if chunk.shape != tuple(chunk_shape[:3]):
37-
padded_chunk = np.zeros(chunk_shape, dtype=chunk.dtype)
38-
padded_chunk[: chunk.shape[0], : chunk.shape[1], : chunk.shape[2], :] = (
39-
chunk
40-
)
41-
return padded_chunk
42-
return chunk
43-
44-
def chunk_size(x_i, y_i, z_i, c):
45-
x_start, x_end = x_i * chunk_shape[0], min((x_i + 1) * chunk_shape[0], shape[0])
46-
y_start, y_end = y_i * chunk_shape[1], min((y_i + 1) * chunk_shape[1], shape[1])
47-
z_start, z_end = z_i * chunk_shape[2], min((z_i + 1) * chunk_shape[2], shape[2])
48-
49-
return (x_end - x_start, y_end - y_start, z_end - z_start, 1)
50-
51-
lazy_reader = dask.delayed(chunked_reader)
52-
lazy_chunks = [
53-
lazy_reader(x, y, z, c)
54-
for x, y, z, c in itertools.product(*[range(i) for i in num_chunks_per_dim])
55-
]
56-
# chunk_sizes = [
57-
# chunk_size(x, y, z, c)
58-
# for x, y, z, c in itertools.product(*[range(i) for i in num_chunks_per_dim])
59-
# ]
60-
sample = lazy_chunks[
61-
0
62-
].compute() # load the first chunk (assume rest are same shape/dtype)
63-
arrays = [
64-
dask.array.from_delayed(lazy_chunk, dtype=sample.dtype, shape=sample.shape)
65-
for lazy_chunk in lazy_chunks
15+
FILEPATH = Path(
16+
"/media/starfish/Storage/metacell/Isl1-GFP_E13-5_F129-3_CMN-R-L_02052024-GLC-stitched.ome.tiff"
17+
)
18+
OUTPUT_PATH = Path(
19+
"/media/starfish/Storage/metacell/converted/Isl1-GFP_E13-5_F129-3_CMN-R-L_02052024-GLC-stitched"
20+
)
21+
OUTPUT_PATH.mkdir(exist_ok=True, parents=True)
22+
23+
# %% Load the data
24+
br = BioReader(str(FILEPATH), backend="bioformats")
25+
26+
# %% Inspect the data
27+
with open(OUTPUT_PATH / "metadata.txt", "w") as f:
28+
json.dump(br.metadata.model_dump_json(), f)
29+
f.write(br.metadata.model_dump_json())
30+
print(br.shape)
31+
32+
# %% Extract from the data - units are in nm
33+
size_x = br.metadata.images[0].pixels.physical_size_x
34+
if size_x is None:
35+
size_x = 1
36+
size_y = br.metadata.images[0].pixels.physical_size_y
37+
if size_y is None:
38+
size_y = 1
39+
size_z = br.metadata.images[0].pixels.physical_size_z
40+
if size_z is None:
41+
size_z = 1
42+
x_unit = br.metadata.images[0].pixels.physical_size_x_unit
43+
y_unit = br.metadata.images[0].pixels.physical_size_y_unit
44+
z_unit = br.metadata.images[0].pixels.physical_size_z_unit
45+
46+
# if the the units are um, convert to nm
47+
if str(x_unit) == "UnitsLength.MICROMETER":
48+
size_x *= 1000
49+
if str(y_unit) == "UnitsLength.MICROMETER":
50+
size_y *= 1000
51+
if str(z_unit) == "UnitsLength.MICROMETER":
52+
size_z *= 1000
53+
54+
num_channels = br.shape[-1]
55+
data_type = "uint16"
56+
chunk_size = [256, 256, 128, 1]
57+
58+
# %% Setup the cloudvolume info
59+
info = CloudVolume.create_new_info(
60+
num_channels=num_channels,
61+
layer_type="image",
62+
data_type=data_type,
63+
encoding="raw",
64+
resolution=[size_x, size_y, size_z],
65+
voxel_offset=[0, 0, 0],
66+
chunk_size=chunk_size[:-1],
67+
volume_size=[br.shape[0], br.shape[1], br.shape[2]],
68+
)
69+
vol = CloudVolume("file://" + str(OUTPUT_PATH), info=info)
70+
vol.provenance.description = "Example data conversion"
71+
vol.commit_info()
72+
vol.commit_provenance()
73+
74+
# %% Setup somewhere to hold progress
75+
progress_dir = OUTPUT_PATH / "progress"
76+
progress_dir.mkdir(exist_ok=True)
77+
78+
79+
# %% Functions for moving data
80+
shape = np.array(br.shape)
81+
chunk_shape = np.array([1024, 1024, 512, 1]) # this is for reading data
82+
num_chunks_per_dim = np.ceil(shape / chunk_shape).astype(int)
83+
84+
85+
def chunked_reader(x_i, y_i, z_i, c):
86+
x_start, x_end = x_i * chunk_shape[0], min((x_i + 1) * chunk_shape[0], shape[0])
87+
y_start, y_end = y_i * chunk_shape[1], min((y_i + 1) * chunk_shape[1], shape[1])
88+
z_start, z_end = z_i * chunk_shape[2], min((z_i + 1) * chunk_shape[2], shape[2])
89+
90+
# Read the chunk from the BioReader
91+
chunk = br.read(X=(x_start, x_end), Y=(y_start, y_end), Z=(z_start, z_end), C=(c,))
92+
return np.expand_dims(chunk, axis=-1)
93+
94+
95+
def process(args):
96+
x_i, y_i, z_i, c = args
97+
rawdata = chunk = chunked_reader(x_i, y_i, z_i, c)
98+
start = [x_i * chunk_shape[0], y_i * chunk_shape[1], z_i * chunk_shape[2]]
99+
end = [
100+
min((x_i + 1) * chunk_shape[0], shape[0]),
101+
min((y_i + 1) * chunk_shape[1], shape[1]),
102+
min((z_i + 1) * chunk_shape[2], shape[2]),
66103
]
67-
x = dask.array.concatenate(arrays)
68-
print(x.shape, shape, np.prod(x.shape), np.prod(padded_chunk_shape))
69-
# We need to reshape in iterations,
70-
# x.reshape(padded_chunk_shape)
71-
scales = [1, 1, 1, 1]
72-
dimensions = neuroglancer.CoordinateSpace(
73-
names=["x", "y", "z", "c"], units="um", scales=scales
74-
)
75-
local_volume = neuroglancer.LocalVolume(x, dimensions)
76-
state.layers.append(
77-
name=name,
78-
layer=neuroglancer.ImageLayer(
79-
source=local_volume,
80-
volume_rendering_mode="ON",
81-
volume_rendering_depth_samples=400,
82-
),
83-
shader="""
84-
#uicontrol invlerp normalized
85-
void main() {
86-
float val = normalized();
87-
emitRGBA(vec4(val, val, val, val));
88-
}
89-
""",
104+
vol[start[0] : end[0], start[1] : end[1], start[2] : end[2], c] = rawdata
105+
touch(
106+
progress_dir
107+
/ f"{start[0]}-{end[0]}_{start[1]}-{end[1]}_{start[2]}-{end[2]}_{c}.done"
90108
)
91-
state.layout = "3d"
92109

93110

94-
def launch_nglancer():
95-
ap = argparse.ArgumentParser()
96-
neuroglancer.cli.add_server_arguments(ap)
97-
args = ap.parse_args()
98-
neuroglancer.cli.handle_server_arguments(args)
99-
viewer = neuroglancer.Viewer()
100-
return viewer
111+
# %% Try with a single chunk to see if it works
112+
# x_i, y_i, z_i = 0, 0, 0
113+
# process((x_i, y_i, z_i, 0))
114+
115+
# %% Can't figure out the writing so do it with fake data
116+
# fake_data = np.random.randint(0, 2**16, size=chunk_size, dtype=np.uint16)
117+
# vol[0:256, 0:256, 0:128, 0] = fake_data
118+
119+
coords = itertools.product(
120+
range(num_chunks_per_dim[0]),
121+
range(num_chunks_per_dim[1]),
122+
range(num_chunks_per_dim[2]),
123+
range(num_channels),
124+
)
101125

126+
# %% Move the data across with multiple workers
127+
# max_workers = 8
102128

103-
def main():
104-
viewer = launch_nglancer()
105-
with viewer.txn() as s:
106-
add_image_layer(s, FILEPATH, "image")
107-
webbrowser.open_new(viewer.get_viewer_url())
129+
# with ProcessPoolExecutor(max_workers=max_workers) as executor:
130+
# executor.map(process, coords)
108131

132+
# %% Move the data across with a single worker
133+
for coord in coords:
134+
process(coord)
109135

110-
if __name__ == "__main__":
111-
main()
136+
# %% Serve the dataset to be used in neuroglancer
137+
vol.viewer(port=1337)

0 commit comments

Comments
 (0)