-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathindex.html
More file actions
372 lines (333 loc) · 16 KB
/
Copy pathindex.html
File metadata and controls
372 lines (333 loc) · 16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ome-zarr.js</title>
<style>
body {
font-family: Arial, sans-serif;
}
img {
margin: 10px;
}
.lut {
display: inline-block;
margin: 2px;
text-align: center;
}
.lut img {
margin: 1px;
width: 256px;
height: 15px;
}
.checquers {
/* background pattern for transparency */
background: linear-gradient(45deg, #ccc 25%, transparent 25%),
linear-gradient(-45deg, #ccc 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #ccc 75%),
linear-gradient(-45deg, transparent 75%, #ccc 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}
.fadeInOut {
animation: fadeInOut 3s ease-in-out infinite;
}
@keyframes fadeInOut {
0%, 100% { opacity: 1; }
50% { opacity: 0.1; }
}
#tiles {
clear: both;
}
#tiles img {
margin: 0;
}
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1px;
width: fit-content;
margin: 10px;
float: left;
}
</style>
</head>
<body>
<h2>render()</h2>
<p>Default thumbnail is smallest multiscales resolution:</p>
<code><pre>
let thumbSrc = await omezarr.render(url);
document.getElementById("thumbnail").src = thumbSrc;
</pre></code>
<div id="thumbnails"></div>
<p>If we know that all images are similar, we can just load the "multiscales" group for 1 image,
then use that to render the others based on full array URL for each e.g. <code>url/to/image.zarr/scale2/</code>.
</p>
<div id="wells"></div>
<p>We can find a labels image, render it with glasbey_inverted.lut and overlay it on the original image.</p>
<div id="labels"></div>
<p>Render tiles: tile size 200 x 200 pixels</p>
<div id="tiles"></div><div style="clear: both;"></div>
<p>We can specify a targetSize to pick a larger multiscales resolution to render.
If autoBoost" is true, contrast will be boosted if needed.</p>
<div id="bigThumbnails"></div>
<p>We can choose various rendering settings etc. "Inverted" is a orthogonal view</p>
<div id="splitview"></div>
<p>A smaller resolution "1", at various z-indeces with Look-up table "16_colors.lut"</p>
<div id="stack"></div>
<h2>Look-up tables available to choose</h2>
<div id="luts"></div>
<script type="module">
async function renderTiles() {
let url = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.5/idr0066/ExpD_chicken_embryo_MIP.ome.zarr";
// This loads the first dataset array, so we know it's shape...
let img = await omezarr.NgffImage.load(url);
// Calulate the shape of other arrays using 'scale' transforms
let shapes = await img.calcShapes();
// [8978, 6510], [4489, 3255], [2244, 1627], [1122, 813], [561, 406], [280, 203], [140, 101], [70, 50]
let shape = shapes[0];
let sizeX = shape[shape.length - 1];
let sizeY = shape[shape.length - 2];
let tileSize = 200;
let xOrig = 3000 / sizeX;
let yOrig = 4000 / sizeY;
for (let dsIndex in [0, 1, 2, 3, 4]) {
let shape = shapes[dsIndex];
let x = Math.floor(xOrig * shape[shape.length - 1]);
let y = Math.floor(yOrig * shape[shape.length - 2]);
// render 4 tiles from the first dataset array
let src1 = await img.render({arrayPathOrIndex: dsIndex, slices:{"x":[x, x + tileSize], "y":[y, y + tileSize]}})
let src2 = await img.render({arrayPathOrIndex: dsIndex, slices:{"x":[x + tileSize, x + 2 * tileSize], "y":[y, y + tileSize]}})
let src3 = await img.render({arrayPathOrIndex: dsIndex, slices:{"x":[x, x + tileSize], "y":[y + tileSize, y + 2 * tileSize]}})
let src4 = await img.render({arrayPathOrIndex: dsIndex, slices:{"x":[x + tileSize, x + 2 * tileSize], "y":[y + tileSize, y + 2 * tileSize]}})
let html = `<div class="grid">
<img src="${src1}" />
<img src="${src2}" />
<img src="${src3}" />
<img src="${src4}" />
</div>`;
document.getElementById("tiles").innerHTML += html;
}
}
async function renderSimilarThumbs() {
let plateUrl = "https://livingobjects.ebi.ac.uk/bioimaging-integrator-data/S-BIAD885/e7bdccbf-5119-4d9c-b466-66d211871db8/e7bdccbf-5119-4d9c-b466-66d211871db8.zarr";
let a1Img = await omezarr.NgffImage.load(plateUrl + "/A/1/0");
// a1Img.omero.channels[0].active = false;
let dsPath = await a1Img.getPathForTargetSize(100);
console.log("dsPath", dsPath);
for (let well of ["A/1/0", "A/2/0", "A/3/0", "A/4/0", "A/5/0", "A/6/0"]) {
let arrUrl = plateUrl + "/" + well + "/" + dsPath;
let src = await a1Img.render({arr: arrUrl, autoBoost: true});
let html = `<img title="${well}" src="${src}" />`;
document.getElementById("wells").innerHTML += html;
}
}
function addRgbaArrays(imgArr, labelArr) {
if (imgArr.length !== labelArr.length) {
throw new Error("Arrays must have the same length");
}
let result = new Uint8ClampedArray(imgArr.length);
for (let i = 0; i < imgArr.length; i++) {
result[i] = Math.min(labelArr[i] || imgArr[i], 255);
}
return result;
}
async function renderLabels() {
let imgUrl = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.4/idr0079A/idr0079_images.zarr/2/";
let img = await omezarr.NgffImage.load(imgUrl);
img.setChannelColor(0, "FF00FF");
img.setChannelEnd(0, 100);
// render the DAPI channel with a custom color map, to show we can use a colormap for an image channel, not just labels
let rgbMap = new Map();
// values below 20 are green, values 50 - 100 are blue
for (let i = 0; i < 20; i++) {
rgbMap.set(i, [0, 255, 0]);
}
for (let i = 50; i < 100; i++) {
rgbMap.set(i, [0, 0, 255]);
}
img.setChannelColorMap(1, rgbMap);
let imsSrc = await img.render({targetSize: 300});
let html = `<a href="${imgUrl}"><img src="${imsSrc}" /></a>`;
document.getElementById("labels").innerHTML += html;
let labelPaths = await img.getLabelsPaths();
// we use `LabelsImage` since it won't scale values when rendering...
let labelImage = await omezarr.LabelsImage.load(imgUrl + "labels/" + labelPaths[0]);
let glasbeyInvertedMap = new Map();
// We only want to see first 100 labels
for (let i = 1; i < 101; i++) {
// label 1 is first color LUT[0], label 2 is LUT[1] etc. (label 0 is background)
glasbeyInvertedMap.set(i, omezarr.luts.GLASBEY_INVERTED[i - 1]);
}
// set label 0 (background) to grey with some transparency
glasbeyInvertedMap.set(0, [100, 100, 100, 100]);
// set missing values to Yellow
glasbeyInvertedMap.set(omezarr.FILL_VALUE_KEY, [255, 255, 0, 100]);
labelImage.setChannelColorMap(0, glasbeyInvertedMap);
let labelSrc = await labelImage.render({targetSize: 512});
html = `<a href="${imgUrl}labels/${labelPaths[0]}"><img class="checquers" src="${labelSrc}" /></a>`;
document.getElementById("labels").innerHTML += html;
// transparent (background), then glasbey_inverted for labels
// We use just 100 colors from the LUT; values over 100 are moduloed back to the start of the LUT
// the FIRST 100 labels will be identical to the colorMap example above...
labelImage.setChannelLut(0, [[255, 0, 0, 0], ...omezarr.luts.GLASBEY_INVERTED.slice(0, 100)]);
labelSrc = await labelImage.render({targetSize: 512});
html = `<a href="${imgUrl}labels/${labelPaths[0]}"><img class="checquers" src="${labelSrc}" /></a>`;
document.getElementById("labels").innerHTML += html;
// Alternatively, we can set ALL labels to the same color:
labelImage.setChannelLut(0, [[255, 0, 0, 0], [0, 255, 255]]);
labelSrc = await labelImage.render({targetSize: 512});
html = `<a href="${imgUrl}labels/${labelPaths[0]}"><img class="checquers" src="${labelSrc}" /></a>`;
document.getElementById("labels").innerHTML += html;
}
import * as zarr from "https://cdn.jsdelivr.net/npm/zarrita@next/+esm";
import { ZipFileStore } from "@zarrita/storage";
const omezarr = await import("/src/index.ts");
let url = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.5/idr0062A/6001240_labels.zarr";
// Load the zarr.json to test {attrs} option.
let zarrJson = await fetch(url + "/zarr.json").then((res) => res.json());
let attrs = zarrJson.attributes; // v0.6 (zarr v3) nested attributes
// This loads the first dataset array, so we know the image dimensions,
let i = await omezarr.NgffImage.load(url, {attrs});
console.log("VERSION", i.getVersion());
console.log("ZARR VERSION", i.getZarrVersion());
console.log("SCALES", i.getScales());
console.log("SHAPE", await i.getShape());
console.log("SHAPES", await i.calcShapes());
console.log("NEUROGLANCER URL", await i.getNeuroglancerUrl());
renderLabels();
renderSimilarThumbs();
renderTiles();
const OXZ = "https://livingobjects.ebi.ac.uk/bioimaging-sandbox/testbucket-bia/test-ozx/6001240.ozx";
const IDR0079_2_LABELS = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.4/idr0079A/idr0079_images.zarr/2/";
const IDR0062 =
"https://livingobjects.ebi.ac.uk/idr/zarr/v0.4/idr0062A/6001240_ngff-zarr.ome.zarr"; // OME-Zarr v0.4
const IDR0048 =
"https://livingobjects.ebi.ac.uk/idr/zarr/v0.4/idr0048A/9846151.zarr/0/";
const IDR0083 =
"https://livingobjects.ebi.ac.uk/idr/zarr/v0.4/idr0083A/9822152.zarr";
const IDR0066 = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.5/idr0066/ExpD_chicken_embryo_MIP.ome.zarr"; // OME-Zarr v0.5
// v0.1 (no axes)
const IDR0077 = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.1/9836841.zarr";
// v0.2 (no axes)
const IDR0070 = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.2/idr0070A/9838562.zarr/0/";
// v0.3
const IDR0079 = "https://livingobjects.ebi.ac.uk/idr/zarr/v0.3/idr0079A/9836998.zarr";
// https://github.com/BioNGFF/ome-zarr.js/issues/9
const TEST_INT64 = "https://s3.janelia.org/funceworm/test-uint64-small.zarr/";
// v0.6 (coordinateSystems instead of axes)
const V06_IDR067 = "https://livingobjects.ebi.ac.uk/idr/zarr/test-data/v0.6dev2/idr0067/9036345_tiles.zarr/9036345_cropped_200_200_200_200_rot30.zarr/";
// Thumbnails...
const urls = [
OXZ,
IDR0079_2_LABELS,
IDR0079_2_LABELS + "labels/0/",
IDR0077,
IDR0083,
IDR0070,
IDR0079,
IDR0062,
IDR0066,
// "https://animatedcell-test-data.s3.us-west-2.amazonaws.com/variance/40.zarr", // 'omero' has lots of white channels
IDR0048,
TEST_INT64,
V06_IDR067,
];
document.getElementById("thumbnails").innerHTML = `<p>Expected ${urls.length} thumbnails...</p>`;
let abortController = new AbortController();
let signal = abortController.signal;
// We can abort... - Try uncommenting this code - thumbnails should be aborded.
// setTimeout(() => {
// abortController.abort(); // abort all thumbnail requests after 1 seconds (for testing cancellation)
// console.log("Aborted thumbnail requests");
// }, 1000);
for (let url of urls) {
console.log("Rendering thumbnail for ", url);
try {
console.log("Signal aborted?", signal.aborted);
// let thumbSrc = await omezarr.render(url);
if (url.endsWith(".ozx")) {
url = ZipFileStore.fromUrl(url);
}
let ngffImg = await omezarr.NgffImage.load(url);
let thumbSrc = await ngffImg.render({targetSize: 100, signal});
let ngHref = typeof url === "string" ? await ngffImg.getNeuroglancerUrl() : "no url";
let html = `<a target="_blank" href="${ngHref}"><img title="${url}" src="${thumbSrc}" /></a>`;
document.getElementById("thumbnails").innerHTML += html;
} catch (error) {
console.error("Error rendering thumbnail for ", url, error);
if (!signal.aborted) {
alert(`Error rendering thumbnail for ${url}: ${error}`);
}
}
}
let thumbSrc = await omezarr.render(IDR0066, undefined, {datasetIndex: 7});
let bigImg = `<img src="${thumbSrc}" />`;
document.getElementById("bigThumbnails").innerHTML += bigImg;
thumbSrc = await omezarr.render(IDR0066, undefined, {datasetIndex: 6});
bigImg = `<img src="${thumbSrc}" />`;
document.getElementById("bigThumbnails").innerHTML += bigImg;
// legacy API - keep a single test for this...
thumbSrc = await omezarr.renderThumbnail(IDR0066, 300, true);
bigImg = `<img src="${thumbSrc}" />`;
document.getElementById("bigThumbnails").innerHTML += bigImg;
// Check we can set channel setting on 2D image (no "c" axis)
let imgChick = await omezarr.NgffImage.load(IDR0066);
imgChick.setChannelLut(0, omezarr.luts.FIRE);
let chickSrc = await imgChick.render({targetSize: 300});
document.getElementById("bigThumbnails").innerHTML += `<img src="${chickSrc}" />`;
// For rendering Images, we want to keep the zarr array in hand...
// const store62 = new zarr.FetchStore(IDR0062);
const img = await omezarr.NgffImage.load(IDR0062);
// arr will be full-sized array by default
// const {arr, omero, multiscale, shapes, zarr_version} = await omezarr.getMultiscaleWithArray(store62);
// turn OFF all channels
for (let channel in img.omero.channels) {
img.setChannelActive(channel, false);
}
img.setChannelColor(0, "00FF00");
img.setChannelColor(1, "FF00FF");
// progressively turn channels on and render...
for (let channel in img.omero.channels) {
img.setChannelActive(channel, true);
let src = await img.render({targetSize: 300});
let html = `<img src="${src}" />`;
document.getElementById("splitview").innerHTML += html;
};
// Inverted image - orthogonal view
img.setChannelInverted(0, true);
let slices62 = {"x": 130, "z": [0, 236]}; // "y" is full range by default
let orthSrc = await img.render({targetSize: 300, slices: slices62});
let html = `<img src="${orthSrc}" />`;
document.getElementById("splitview").innerHTML += html;
// get a smaller array for Z-stack
console.log("idr0062 shapes", img.shapes); // [2, 236, 275, 271], [2, 236, 138, 136], [2, 236, 69, 68]
// const paths = img.multiscale.datasets.map((d) => d.path);
console.log("idr0062 paths", img.paths);
const pathOrIndex = 1;
const arr200 = await img.openArray(pathOrIndex);
// turn first channel ON, use LUT
img.setChannelActive(0, true);
img.setChannelActive(1, false);
img.setChannelLut(0, omezarr.luts.SIXTEEN_COLORS);
img.setChannelInverted(0, false);
// TODO: use dim names from multiscale
let sizeZ = arr200.shape.at(-3);
let interval = Math.ceil(sizeZ / 7);
for (let zSlice = interval; zSlice <= sizeZ; zSlice += interval) {
img.setZIndex(zSlice);
let src = await img.render({arr: arr200});
let html = `<img src="${src}" title="Z: ${zSlice}"/>`;
document.getElementById("stack").innerHTML += html;
}
// show luts
omezarr.getLuts().forEach((lut) => {
let src = lut.png;
let html = `<div class="lut"><legend>${lut.name}</legend>
<img class="lut" src="${src}" title="${lut.name}" /></div>`;
document.getElementById("luts").innerHTML += html;
});
</script>
</body>
</html>