Skip to content

Commit f2c0794

Browse files
committed
feat: add in progress sis example
1 parent a4506c2 commit f2c0794

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

examples/load_sis.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import argparse
2+
import webbrowser
3+
import neuroglancer
4+
import neuroglancer.cli
5+
from pathlib import Path
6+
import dask.array as da
7+
import numpy as np
8+
9+
HERE = Path(__file__).parent
10+
# path to the file
11+
FILEPATH = Path("x.sis")
12+
13+
14+
class OlympusSISFile:
15+
def __init__(self, path):
16+
self._path = path
17+
self._file = open(path, "rb")
18+
self._get_header_size()
19+
self._file.seek(self.header_size)
20+
21+
# TEMP - hardcoded values from metadata
22+
# Something is a litte wrong though as it's too big
23+
self.width = 3299
24+
self.height = 3289
25+
self.depth = 10 # actual 1025
26+
self.channels = 1 # actual 9
27+
28+
def read(self, size=-1):
29+
return self._file.read(size)
30+
31+
def seek(self, offset, whence=0):
32+
if whence == 0:
33+
return self._file.seek(self.header_size + offset)
34+
elif whence == 1:
35+
return self._file.seek(offset, 1)
36+
elif whence == 2:
37+
return self._file.seek(offset, 2)
38+
39+
def tell(self):
40+
return self._file.tell() - self.header_size
41+
42+
def close(self):
43+
self._file.close()
44+
45+
def __enter__(self):
46+
return self
47+
48+
def __exit__(self, exc_type, exc_val, exc_tb):
49+
self.close()
50+
51+
def _get_header_size(self):
52+
i = 0
53+
while True and i < 1000000:
54+
line = self._file.readline().decode("utf-8")
55+
i += 1
56+
if line.startswith("Header"):
57+
break
58+
# The format is Header = <size>
59+
# 49 chars for the bit before Header = <size>
60+
self.header_size = int(line.split("=")[1].strip()) + 49
61+
print(f"Header size: {self.header_size}")
62+
63+
def write_header_to_file(self, path):
64+
self._file.seek(0)
65+
with open(path, "wb") as f:
66+
f.write(self._file.read(self.header_size))
67+
self._file.seek(self.header_size)
68+
69+
def to_numpy_memmap(self):
70+
return np.memmap(
71+
self._path,
72+
offset=self.header_size,
73+
dtype=np.uint16,
74+
mode="r",
75+
shape=(self.height, self.width, self.depth, self.channels),
76+
)
77+
78+
79+
def add_image_layer(state, data, name="image"):
80+
dimensions = neuroglancer.CoordinateSpace(
81+
names=["x", "y", "z", "c"], units="nm", scales=[1, 1, 1, 1]
82+
)
83+
local_volume = neuroglancer.LocalVolume(data, dimensions)
84+
state.layers.append(
85+
name=name,
86+
layer=neuroglancer.ImageLayer(
87+
source=local_volume,
88+
volume_rendering_mode="ON",
89+
volume_rendering_depth_samples=400,
90+
),
91+
shader="""
92+
#uicontrol invlerp normalized
93+
void main() {
94+
float val = normalized();
95+
emitRGBA(vec4(val, val, val, val));
96+
}
97+
""",
98+
)
99+
state.layout = "3d"
100+
101+
102+
def launch_nglancer():
103+
ap = argparse.ArgumentParser()
104+
neuroglancer.cli.add_server_arguments(ap)
105+
args = ap.parse_args()
106+
neuroglancer.cli.handle_server_arguments(args)
107+
viewer = neuroglancer.Viewer()
108+
return viewer
109+
110+
111+
def main():
112+
chunks = (512, 512, 1, 1)
113+
with OlympusSISFile(str(FILEPATH)) as f:
114+
f.write_header_to_file("header.txt")
115+
mmapped = f.to_numpy_memmap()
116+
# TODO would need to replace with a lazy load from the mmap
117+
dask_array = da.from_array(mmapped, chunks=chunks)
118+
viewer = launch_nglancer()
119+
with viewer.txn() as s:
120+
add_image_layer(s, dask_array, "image")
121+
webbrowser.open_new(viewer.get_viewer_url())
122+
123+
124+
if __name__ == "__main__":
125+
main()

0 commit comments

Comments
 (0)