Giter VIP home page Giter VIP logo

n5-ij's Introduction

n5-ij Build Status

A Fiji plugin for loading and saving image data to N5 containers. Supports HDF5, Zarr, Amazon S3, and Google cloud storage.

Contents

  1. Open N5
    1. Virtual
    2. Cropping
  2. Export N5
  3. Container types
  4. Metadata
  5. For developers
  6. Details
    1. Cloud writing benchmarks

Open N5

Open N5 datasets from Fiji with File > Import > N5.

Quickly open a dataset by pasting the full path to the dataset and press OK. For example, try gs://example_multi-n5_bucket/mitosis.n5/raw to open the sample mitosis image from Google cloud storage.

Click the Browse button to select a folder on your filesystem.

The detected datasets will be displayed in the dialog. Select (highlight) the datasets you would like to open and press OK. In the example below, we will open the datasets /blobs, and /t1-head/c0/s0.

Virtual

Check the Open as virtual box to open the n5 dataset as a virtual stack in ImageJ. This enable the opening and viewing of image data that do not fit in RAM. Image slices are loaded on-the-fly, so navigation will be slow when parts of the images are loaded.

Cropping

Subsets of images can be opened by checking the Crop box in the dialog, then pressing OK. A separate dialog will appear for each selected dataset as shown below.

Give the min and max values for the field-of-view to open in pixel / voxel units a particular subset. The opened interval includes both min and max values, so the image will be of size max - min + 1 along each dimension. In the example shown above, the resulting image will be of size 101 x 111 x 2 x 51.

Export N5

Save images opened in Fiji as N5 datasets with File > Save As > Export N5.

Parameters

  • N5Root - the root location of the n5 (see also Container types)
  • Dataset - the name of the dataset.
  • Chunk size - chunk/block size as comma-separated list.
    • ImageJ's axis order is X,Y,C,Z,T. The chunk size must be specified in this order. You must skip any axis whose size is 1, e.g. a 2D time-series without channels may have a chunk size of 1024,1024,1 (X,Y,T).
    • You may provide fewer values than the data dimension. In that case, the list will be expanded to necessary size with the last value, for example 64, will expand to 64,64,64 for 3D data.
  • Create Pyramid - If checked, a multiscale pyramid will be created (if possible). See below for details.
  • Downsampling method - The downsampling method to be used if a multiscale pyramid can be created. See below for details.
  • Compression - The compression method to be used for chucnks / blocks.
  • metadata type - style and type of metadata to store (see also Metadata)
  • thread count - number of threads used for parallel writing (see also Cloud writing benchmarks)
  • Overwrite - If checked, existing data may be deleted and overwritten without warning.

Container types

The export plugin infers container type from the file/directory path or url given as the n5 root:

  • Filesystem N5
    • Specify a directory ending in .n5
    • example /path/to/my/data.n5
  • Zarr
    • Specify a directory ending in .zarr
    • example /Users/user/Documents/sample.zarr
  • HDF5
    • Specify a file ending in .h5 ,.hdf5, or .hdf
    • example C:\user\docs\example.h5
  • Amazon S3
    • Specify one of two url styles:
    • s3://bucket-name/path/to/root.n5
    • https://bucket-name.s3.amazonaws.com/path/to/root.n5
  • Google cloud storage (one of two url styles)
    • Specify one of two url styles:
    • gs://bucket-name/path/inside/bucket/root.n5
    • https://bucket-name.s3.amazonaws.com/path/to/root.n5

Multi-scale pyramids

How many scale levels will be created

The number of scale levels is determined by the image size and specified block size. The exporter will downsample an image only if the block size is striclty smaller than the image size in every dimension.

Example 1

If image size is 100 x 100 x 100 and the block size is 100 x 100 x 100 will write one scale level because the whole image fits into one block at the first scale level.

Example 2

If image size is 100 x 100 x 100 and the block size is 64 x 64 x 64 will write two scale levels: The first scale level will have a 2 x 2 x 2 grid of blocks.

Example 3

If image size is 100 x 100 x 32 and the block size is 64 x 64 x 64 will write one scale level because the third dimension of the image is smaller than the third dimension of the block.

Downsampling

The N5 exporter always downsamples images by factors of two in all dimensions. There are two downsampling methods:

Sample

N5 will take even-indexed samples and discard odd-indexed samples along each dimension.

Averaging

N5 will average adjacent samples along each dimension. This results in a "half-pixel" shift, which will be reflected in the metadata.

Overwriting

Warning messages

If the overwrite option is not selected in the dialog, the exporter will determine if the write operation would overwrite or invalidate existing data. If so, it prompts the user with a warning dialog, asking if data should be overwritten.

Data could be overwritten if:

  • the path where data will be written already exists and contains data.
  • a parent of the path where data will be written already exists and contains data.
    • here, the newly written data would be inaccessible, because data arrays must be leafs of the hierarchy tree.

If the overwrite option is selected in the initial dialog, the user will not be prompted, but data will be overwritten if needed as explained below.

Example 1

A dataset exists at /image. User attempts to write data into /image. This warns the user about overwriting because an array already exists at that location.

Example 2

A dataset exists at /data/s0. User attempts to write data into /data using N5Viewer metadata. This warns the user about overwriting because when writing N5Viewer metadata, the plugin will write the full resolution level of the multiscale pyramid at location /data/s0, but an array already exists at that location.

Overwriting removes existing data

If the user decides to overwite data the N5 exporter will completely (array data and metadata) remove any groups that cause conflicts before writing the new data.

  • If a dataset already exists at a path where new data will be written, then all data at that path will be removed.
  • If a dataset already exists at a parent path where new data will be written, then all data at that parent path will be removed.

Example 3

A dataset exists at /image. User attempts to write data into /image/channel0. This warns the user about overwriting because the newly written data would be a child path of existing data, and therefore be invalid. If the user decides to overwrite, all data at /image will be removed before writing the new data to /image/channel0.

Metadata

This plugin supports three types of image metadata:

  1. ImageJ-style metadata
  2. N5-viewer metadata
  3. COSEM metadata
  4. Custom metadata. Read details here

The metadata style for exported N5 datasets is customizable, more detail coming soon.

For developers

ImageJ convenience layer for N5

Build into your Fiji installation:

mvn -Dscijava.app.directory=/home/saalfelds/packages/Fiji.app -Ddelete.other.versions=true clean install

Then, in Fiji's Script Interpreter (Plugins > Scripting > Script Interpreter), load an N5 dataset into an ImagePlus:

import org.janelia.saalfeldlab.n5.*;
import org.janelia.saalfeldlab.n5.ij.*;

imp = N5IJUtils.load(new N5FSReader("/home/saalfelds/example.n5"), "/volumes/raw");

or save an ImagePlus into an N5 dataset:

import ij.IJ;
import org.janelia.saalfeldlab.n5.*;
import org.janelia.saalfeldlab.n5.ij.*;

N5IJUtils.save(
    IJ.getImage(),
    new N5FSWriter("/home/saalfelds/example.n5"),
    "/volumes/raw",
    new int[] {128, 128, 64},
    new GzipCompression()
);

Save an image stored locally to cloud storage (using four threads):

final ImagePlus imp = IJ.openImage( "/path/to/some.tif" );
final ExecutorService exec = Executors.newFixedThreadPool( 4 );
N5IJUtils.save( imp, 
    new N5Factory().openWriter( "s3://myBucket/myContainer.n5" ), 
    "/myDataset", 
	new int[]{64, 64, 64},
	new GzipCompression(), 
	exec );
exec.shutdown();

See also scripts demonstrating

Details

  • This plugin supports images of up to 5 dimensions, and the datatypes supported by ImageJ (uint8, uint16, float32) For higher dimensions and other datatypes, we recommend n5-imglib2.

  • This plugin supports only the datatypes supported by ImageJ, namely uint8, uint16, and float32. For other datatypes, use n5-imglib2.

Cloud writing benchmarks

Below are benchmarks for writing images of various sizes, block sizes, and with increasing amount of parallelism.

Amazon S3

Time in seconds to write the image data. Increased parallelism speeds up writing substantially when the total number of blocks is high.

Image size Block size 1 thread 2 threads 4 threads 8 threads 16 threads
64x64x64 32x32x32 0.98 0.60 0.45 0.50 0.51
128x128x128 32x32x32 4.72 2.64 1.62 1.00
256x256x256 32x32x32 37.09 19.11 9.09 5.20 3.2
256x256x256 64x64x64 10.56 5.04 3.23 2.17 1.86
512x512x512 32x32x32 279.28 156.89 74.72 37.15 19.77
512x512x512 64x64x64 76.63 38.16 19.86 10.16 6.14
512x512x512 128x128x128 27.16 14.32 8.01 4.70 3.31
1024x1024x1024 32x32x32 2014.73 980.66 483.04 249.83 122.36
1024x1024x1024 64x64x64 579.46 289.53 149.98 75.85 38.18
1024x1024x1024 128x128x128 203.47 107.23 55.11 27.41 15.33

n5-ij's People

Contributors

axtimwalde avatar bogovicj avatar cmhulbert avatar ctrueden avatar hkmoon avatar igorpisarev avatar stephanpreibisch avatar willgiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

n5-ij's Issues

Can't open n5-viewer after fiji update_error relate to "net/imglib2/display/RealARGBColorConverter$Imp0"

The n5-viewer throws the following error after updating Fiji.

java.lang.NoClassDefFoundError: net/imglib2/display/RealARGBColorConverter$Imp0
at org.janelia.saalfeldlab.n5.bdv.N5Viewer.addSourceToListsRealType(N5Viewer.java:279)
at org.janelia.saalfeldlab.n5.bdv.N5Viewer.addSourceToListsGenericType(N5Viewer.java:242)
at org.janelia.saalfeldlab.n5.bdv.N5Viewer.exec(N5Viewer.java:133)
at org.janelia.saalfeldlab.n5.bdv.N5Viewer.run(N5Viewer.java:88)
at ij.IJ.runUserPlugIn(IJ.java:230)
at ij.IJ.runPlugIn(IJ.java:193)
at ij.Executer.runCommand(Executer.java:137)
at ij.Executer.run(Executer.java:66)
at java.lang.Thread.run(Thread.java:748)

gson error for images having extra dimension of size 1

First of all, it is really great to have the N5 import and export tools now included in Fiji by default! Thanks very much for this effort! I have been meaning to work with N5 for a while and this makes it much easier.

I have been testing importing and exporting with different images and I keep getting an error from gson when it tries to write an NaN (see below). I seem to get this error from images that have an extra dimension of size 1. For example, an image that contains a Z axis but where all T were collected for Z = 0. Something like X, Y, Z, Channel, Time = 1024, 1024, 1, 2, 160. I think somehow the Z dimension in these videos triggers writing the NaN and gson is set to not allow writing of NaN values, perhaps because they would end up being strings and can cause a lot of problems when parsing json later on...

The videos still seem to be written and I can open them. Should I just ignore this error and continue on? Obviously, another solution would be to always work with the minimal dimensions required - to never have dimensions of size 1. But it seems that the SCIFIO reader we are using opens videos this way with some dimensions of size 1. I don't seem to have the issue when opening the videos with IJ1.

I guess the error below is actually coming from the N5Writer and not really the plugins here, but I thought reporting the issue here would be best since it involves the way videos are opened in Fiji. If you want I can report it over there...

Thanks again for this cool format and helpful plugins. If you don't see this as an issue, I get it, and feel free to close it. But please let me know if you have any tips on how I could deal with this.

Screenshot 2020-11-30 at 12 59 46

Invalid path in Import > HDF5/N5/Zarr/OME-NGFF ... crop dialog

Problem

When opening an N5 dataset with the Import > HDF5/N5/Zarr/OME-NGFF ... dialog, it is possible to specify a subfolder of an N5 container rather than the base path. E.g., in the following N5 container, specifying base.n5/grp instead of base.n5 to detect the dataset data.

base.n5/
├── attributes.json
└── grp
    └── data

This is convenient, since dataset detection from the root can take some time if the container contains a large hierarchy.

However, if the crop checkbox is checked, the string which is automatically inserted into the N5 path field of the crop dialog duplicates parts of the paths within the N5 container: instead of base.n5/grp/data it is base.n5/grp/grp/data when base.n5/grp is used in the import dialog. This leads to the following error:

not a dataset : base.n5/grp/grp/data

Workaround

Since the string in the crop dialog can be edited, one can simply fix it manually (which is a bit inconvenient since the field is too small to do this efficiently).

Suggested fix

It seems to me that getN5RootPath() in ui/DatasetSelectorDialog.java does not return the N5 root path but simply the string in the text field of the import dialog. Returning the actual N5 root there would probably fix the problem.

NullPointerException after Browse

Found by Grace Park

Clicking Browse to choose a container from the plugin gave the error

Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
	at java.io.File.<init>(File.java:277)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openBrowseDialog(DatasetSelectorDialog.java:459)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:488)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:477)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$run$2(DatasetSelectorDialog.java:275)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
	at java.awt.Component.processMouseEvent(Component.java:6539)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
	at java.awt.Component.processEvent(Component.java:6304)
	at java.awt.Container.processEvent(Container.java:2239)
	at java.awt.Component.dispatchEventImpl(Component.java:4889)
	at java.awt.Container.dispatchEventImpl(Container.java:2297)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
	at java.awt.Container.dispatchEventImpl(Container.java:2283)
	at java.awt.Window.dispatchEventImpl(Window.java:2746)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
	at java.awt.EventQueue$4.run(EventQueue.java:733)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Feature: File browser

It would be great if the file browser starts in the last selected data path, rather than Documents (on Windows). This will make browsing through multiple datasets easier.

macro recording of crop broken

to reproduce

  1. turn on macro recorder
  2. open an n5 with crop options
  3. observe crop parameters in the recorded macro
  4. run recorded macro
  5. observe that the result is not cropped, but the whole dataset

Threadpool not being "joined" in n5 save()?

Hi!

I've noticed some odd behaviour in a Python script that uses pyimagej to generate and run a BeanScript that invokes N5IJUtils.save(); if I pass a threadpool object to N5IJUtils.save(), the enclosing Python process never seems to actually exit - despite control reaching the end of the Python script.

For example, this invocation of N5IJUtils.save() works fine, with the output correctly generated and the enclosing Python script exiting as expected:

try {
  N5IJUtils.save(
      image_object,
      new N5FSWriter(filepath),
      dataset,
      new int[] {128, 128, 64},
      new GzipCompression()
  );
} catch (Exception e) {
  print(e);
}

However, this invocation results in the process never ending, despite the output being written and control reaching the end of the enclosing Python script:

try {
  N5IJUtils.save(
      image_object,
      new N5FSWriter(filepath),
      dataset,
      new int[] {128, 128, 64},
      new GzipCompression(),
      Executors.newFixedThreadPool(nthreads)
  );
} catch (Exception e) {
  print(e);
}

It seems like the threadpool spawns some sort of rogue background threads or process that's never being join'd?

Thanks!

Progress bar while file saving

When saving an active image window to the N5 format with File > Save as.. > Export N5 is there a way to look at the task progress? Thanks.

java.lang.runtime.exception when opening zarr

Hello.

Great work and many thanks for making this plugin!

I am trying to open a zarr file, but keep running into the following exception.

image

I tried it with "Open as virtual" checked and not. Do you know what went wrong?

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: 1000000
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:78)
	at net.imglib2.img.cell.LazyCellImg$LazyCells.get(LazyCellImg.java:104)
	at net.imglib2.img.list.AbstractLongListImg$LongListRandomAccess.get(AbstractLongListImg.java:274)
	at net.imglib2.img.cell.CellRandomAccess.getCell(CellRandomAccess.java:137)
	at net.imglib2.img.cell.CellRandomAccess.updatePosition(CellRandomAccess.java:475)
	at net.imglib2.img.cell.CellRandomAccess.<init>(CellRandomAccess.java:131)
	at net.imglib2.img.cell.AbstractCellImg.randomAccess(AbstractCellImg.java:104)
	at net.imglib2.img.cell.AbstractCellImg.randomAccess(AbstractCellImg.java:51)
	at net.imglib2.util.Util.getTypeFromInterval(Util.java:806)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.read(N5Importer.java:390)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:510)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:482)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:530)
	at org.janelia.saalfeldlab.n5.ij.N5Importer$1.run(N5Importer.java:568)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.processThread(N5Importer.java:571)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.datasetSelectorCallBack(N5Importer.java:297)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.ok(DatasetSelectorDialog.java:542)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$run$5(DatasetSelectorDialog.java:270)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
	at java.awt.Component.processMouseEvent(Component.java:6535)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
	at java.awt.Component.processEvent(Component.java:6300)
	at java.awt.Container.processEvent(Container.java:2236)
	at java.awt.Component.dispatchEventImpl(Component.java:4891)
	at java.awt.Container.dispatchEventImpl(Container.java:2294)
	at java.awt.Component.dispatchEvent(Component.java:4713)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
	at java.awt.Container.dispatchEventImpl(Container.java:2280)
	at java.awt.Window.dispatchEventImpl(Window.java:2750)
	at java.awt.Component.dispatchEvent(Component.java:4713)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.awt.EventQueue$4.run(EventQueue.java:729)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: 1000000
	at net.imglib2.cache.ref.SoftRefLoaderCache.get(SoftRefLoaderCache.java:145)
	at net.imglib2.cache.util.LoaderCacheAsCacheAdapter.get(LoaderCacheAsCacheAdapter.java:76)
	at net.imglib2.cache.util.CacheAsUncheckedCacheAdapter.get(CacheAsUncheckedCacheAdapter.java:74)
	... 53 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1000000
	at net.imglib2.img.basictypeaccess.array.AbstractByteArray.setValue(AbstractByteArray.java:67)
	at net.imglib2.type.numeric.integer.GenericByteType.setByte(GenericByteType.java:135)
	at org.janelia.saalfeldlab.n5.imglib2.N5CellLoader.lambda$createCopy$1(N5CellLoader.java:191)
	at org.janelia.saalfeldlab.n5.imglib2.N5CellLoader.load(N5CellLoader.java:144)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:124)
	at net.imglib2.cache.img.LoadedCellCacheLoader.get(LoadedCellCacheLoader.java:84)
	at net.imglib2.cache.ref.SoftRefLoaderCache.get(SoftRefLoaderCache.java:135)
	... 55 more

Paintera label-multiset datasets cannot be opened

Datasets of type label-multiset should be open-able by imagej, it should convert to an integer type.

(Found by @jonesa3)

Metadata are parsed and the UI let's you select a label-multiset typed dataset, but whey opening, throws

this error trace
Exception in thread "AWT-EventQueue-1" java.lang.UnsupportedOperationException
	at net.imglib2.type.label.LabelMultisetType.getNativeTypeFactory(LabelMultisetType.java:170)
	at net.imglib2.img.imageplus.ImagePlusImgFactory.create(ImagePlusImgFactory.java:69)
	at net.imglib2.img.imageplus.ImagePlusImgFactory.create(ImagePlusImgFactory.java:76)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.read(N5Importer.java:489)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:624)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:596)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.process(N5Importer.java:651)
	at org.janelia.saalfeldlab.n5.ij.N5Importer$1.run(N5Importer.java:688)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.processThread(N5Importer.java:691)
	at org.janelia.saalfeldlab.n5.ij.N5Importer.datasetSelectorCallBack(N5Importer.java:372)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.ok(DatasetSelectorDialog.java:756)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$6(DatasetSelectorDialog.java:320)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:262)
	at java.awt.Component.processMouseEvent(Component.java:6539)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
	at java.awt.Component.processEvent(Component.java:6304)
	at java.awt.Container.processEvent(Container.java:2239)
	at java.awt.Component.dispatchEventImpl(Component.java:4889)
	at java.awt.Container.dispatchEventImpl(Container.java:2297)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
	at java.awt.Container.dispatchEventImpl(Container.java:2283)
	at java.awt.Window.dispatchEventImpl(Window.java:2746)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
	at java.awt.EventQueue$4.run(EventQueue.java:733)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
	at org.GNOME.Accessibility.AtkWrapper$6.dispatchEvent(AtkWrapper.java:717)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

New feature - add file size

In the 'Open N5' panel, it would be helpful to additonally see the file size (bytes). This will help determine what resolution to open based on your memory. Currently the image dimensions and image type are displayed.

4D zarr datasets not loaded correctly in FIJI

I am using FIJI with ImageJ 1.53q. Looking in the installation direction jars subfolder I find n5-ij-3.2.2.jar and n5-zarr-0.0.7.jar

When I use File -> Import -> N5 to load a 4D zarr dataset, the resulting imagej hyperstack that is produced is not correct. This hyperstack has two sliders, "c" and "z". However, the data from the zarr is not put in the correct place. The data from the "c" and "z" dimensions in the zarr are mixed up in the imagej hyperstack.

A minimal example:
I create a zarr using the following python code

import zarr
import numpy as np

# zarr dimensions
nc = 5
nz = 30
nx = 256
ny = 256

# create zarr
fname = "test.zarr"
data = zarr.open(fname, "w")
data.create_dataset("test", shape=(nc, nz, ny, nx),
                    chunks=(1, nz, ny, nx), dtype='float32', compressor="none")

# zarr values are z-slice coordinates
for ii in range(nc):
    for jj in range(nz):
        data.test[ii, jj] = np.ones((ny, nx)) * jj

Next I open it in FIJI with File -> Import -> N5. Now I expect when I scroll through the "c" channel in the hyperstack that I will not see the value of the image change, since the image value only depends on the z-index. But I do see it change. For example, if I keep the z-index at value 1/30 and scroll the c index I see image values of 0, 1, 2, 3, and 4. If I increment the z-index to 2/30 and scoll c I see 5, 6, 7, 8, and 9.

Feature request: option to generate multichannel/multiscale during export

When exporting N5 it would be nice to have an option to generate a multichannel/multiscale representation as supported by BDV. Meaning:

c0
    s0
    s1
    s2
c1
    s0
    s1
    s2

Etc. Along with the associated multiscale metadata.

I believe that BigStitcher already has this option when resaving to N5, so maybe code could be borrowed from there.

Issue opining up h5 file using N5 plugin - images are blank

Hi!
I'm trying to open some h5 file through import->N5 on image J, but the images turned up to be blank. The file is able to open up properly using the import->HDF5. I wonder what the issue is?

Context: My dataset is very large and exceeds the HDF5 plugin size limit, so I want to use the N5 plugin and use its virtual stack function. The N5 opens the file as blank no matter if the file size is big or small, or if I use virtual stack or not.

Thank you very much!

Screenshot 2024-05-14 at 4 25 38 PM Screenshot 2024-05-14 at 4 25 44 PM Screenshot 2024-05-14 at 4 25 55 PM Screenshot 2024-05-14 at 4 26 22 PM

Consistency between FIJI GUI and N5IJUtils.load()

Hi,

When I save an n5 dataset in the FIJI GUI, it asks me to specify a Dataset. Examining the resultant n5 directory shows a subdirectory with this name, under which all the data appears to be saved. So far so good.

However, trying to read the previously saved n5 data via e.g. a BeanScript using N5IJUtils.load() and passing in the same Dataset value used to generate the n5 output doesn't work; you need to append a bunch of stuff ("/c0/s0") to the Dataset value you previously specified in FIJI to get it to load.

E.g.: If I call my Dataset "default" when writing the n5 in FIJI, I have to use "default/c0/s0" as the Dataset value in N5IJUtils.load().

This is very confusing; why are these Dataset values different for writing and reading to/from the same n5 "file"? Can we rely on adding "/c0/s0" to our Dataset values being stable in the future?

Fiji warning when pulling data from S3

Loading stuff from S3 through Fiji File/Import/N5 and receiving below warning. Plugin still works as expected.

Could not load AWS credentials, falling back to anonymous.
[pool-11-thread-1] ERROR org.janelia.saalfeldlab.n5.N5DatasetDiscoverer - Error encountered during metadata parsing
java.lang.InterruptedException
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:404)
at java.util.concurrent.FutureTask.get(FutureTask.java:191)
at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer.parseMetadataRecursive(N5DatasetDiscoverer.java:510)
at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$openContainer$16(DatasetSelectorDialog.java:657)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Could not load AWS credentials, falling back to anonymous.

Feature: Self-hosted S3 compatible object store

Hey Folks,

I'd like to request a new feature extension to the S3 i/o module -- support for named URLs to support self-hosted store implementations (like MinIO). A lot of file storage kit these days comes with S3 compatible stores so it would be a useful feature to be able to use with these.

Warn users if an array exists, allow overwriting

If an array exists at the user specified path (or at a child of the user specified path),
prompt users with a dialog asking if they want to overwrite the array.

If the users decides to overwrite, delete the path and all children before writing the array.

Feature: Image window name

It would be great if the Fiji image window carries the name of the dataset that is open. Currently all windows are named "(V)" which makes it difficult to navigate multiple open datasets without manually renaming the windows.

h5 parsing throws errors and fails

java.util.concurrent.ExecutionException: java.io.IOException: ncsa.hdf.hdf5lib.exceptions.HDF5SymbolTableException: Symbol table:Inappropriate type ["H5Gint.c line 327 in H5G__open_name(): not a group"]
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog$LoaderSorterAndCallback.run(DatasetSelectorDialog.java:609)
Caused by: java.io.IOException: ncsa.hdf.hdf5lib.exceptions.HDF5SymbolTableException: Symbol table:Inappropriate type ["H5Gint.c line 327 in H5G__open_name(): not a group"]
	at org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader.list(N5HDF5Reader.java:217)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer$1.call(N5DatasetDiscoverer.java:153)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer$1.call(N5DatasetDiscoverer.java:142)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: ncsa.hdf.hdf5lib.exceptions.HDF5SymbolTableException: Symbol table:Inappropriate type ["H5Gint.c line 327 in H5G__open_name(): not a group"]
	at ch.systemsx.cisd.hdf5.hdf5lib.H5.H5Gopen(Native Method)
	at ch.systemsx.cisd.hdf5.hdf5lib.H5GLO.H5Gopen(H5GLO.java:80)
	at ch.systemsx.cisd.hdf5.HDF5.openGroup(HDF5.java:322)
	at ch.systemsx.cisd.hdf5.HDF5$10.call(HDF5.java:423)
	at ch.systemsx.cisd.hdf5.HDF5$10.call(HDF5.java:1)
	at ch.systemsx.cisd.hdf5.cleanup.CleanUpCallable.call(CleanUpCallable.java:40)
	at ch.systemsx.cisd.hdf5.HDF5.getGroupMembers(HDF5.java:436)
	at ch.systemsx.cisd.hdf5.HDF5BaseReader.getAllGroupMembers(HDF5BaseReader.java:773)
	at ch.systemsx.cisd.hdf5.HDF5BaseReader.getGroupMembers(HDF5BaseReader.java:761)
	at ch.systemsx.cisd.hdf5.HDF5ObjectReadOnlyInfoProviderHandler.getGroupMembers(HDF5ObjectReadOnlyInfoProviderHandler.java:424)
	at org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader.list(N5HDF5Reader.java:214)

Opening zarr files with .zattrs

Hello. I noticed that opening .zarr directories that contain .zattrs is not possible. This is the exception:

Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: JsonNull
	at com.google.gson.JsonElement.getAsString(JsonElement.java:179)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrReader.getZArraryAttributes(N5ZarrReader.java:258)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrReader.getDatasetAttributes(N5ZarrReader.java:267)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrReader.datasetExists(N5ZarrReader.java:275)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrReader.exists(N5ZarrReader.java:287)
	at org.janelia.saalfeldlab.n5.N5FSReader.<init>(N5FSReader.java:118)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrReader.<init>(N5ZarrReader.java:100)
	at org.janelia.saalfeldlab.n5.ij.N5Factory.openZarrReader(N5Factory.java:214)
	at org.janelia.saalfeldlab.n5.ij.N5Factory.openReader(N5Factory.java:383)
	at org.janelia.saalfeldlab.n5.ij.N5Importer$N5ViewerReaderFun.apply(N5Importer.java:691)
	at org.janelia.saalfeldlab.n5.ij.N5Importer$N5ViewerReaderFun.apply(N5Importer.java:672)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:548)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:527)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$run$2(DatasetSelectorDialog.java:309)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
	at java.awt.Component.processMouseEvent(Component.java:6539)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
	at java.awt.Component.processEvent(Component.java:6304)
	at java.awt.Container.processEvent(Container.java:2239)
	at java.awt.Component.dispatchEventImpl(Component.java:4889)
	at java.awt.Container.dispatchEventImpl(Container.java:2297)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
	at java.awt.Container.dispatchEventImpl(Container.java:2283)
	at java.awt.Window.dispatchEventImpl(Window.java:2746)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
	at java.awt.EventQueue$4.run(EventQueue.java:733)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Exeception when saving as .zarr

I succeeded in saving a 704x1800x3814 unsigned 16-bit image to .n5 and .h5. When I try to save as .zarr I get the following error:

(Fiji Is Just) ImageJ 2.3.0/1.53q; Java 1.8.0_322 [64-bit]; Windows 10 10.0; 9717MB of 48813MB (19%)
 
java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Module threw exception
	at net.imagej.legacy.LegacyService.runLegacyCompatibleCommand(LegacyService.java:307)
	at net.imagej.legacy.DefaultLegacyHooks.interceptRunPlugIn(DefaultLegacyHooks.java:166)
	at ij.IJ.runPlugIn(IJ.java)
	at ij.Executer.runCommand(Executer.java:152)
	at ij.Executer.run(Executer.java:70)
	at java.lang.Thread.run(Thread.java:750)
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Module threw exception
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at net.imagej.legacy.LegacyService.runLegacyCompatibleCommand(LegacyService.java:303)
	... 5 more
Caused by: java.lang.RuntimeException: Module threw exception
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:127)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:63)
	at org.scijava.thread.DefaultThreadService.lambda$wrap$2(DefaultThreadService.java:225)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	... 1 more
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
	at java.lang.String.substring(String.java:1967)
	at org.janelia.saalfeldlab.n5.zarr.N5ZarrWriter.createDataset(N5ZarrWriter.java:260)
	at org.janelia.saalfeldlab.n5.imglib2.N5Utils.save(N5Utils.java:1315)
	at org.janelia.saalfeldlab.n5.ij.N5IJUtils.save(N5IJUtils.java:254)
	at org.janelia.saalfeldlab.n5.ij.N5IJUtils.save(N5IJUtils.java:219)
	at org.janelia.saalfeldlab.n5.ij.N5IJUtils.save(N5IJUtils.java:191)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.write(N5Exporter.java:332)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.process(N5Exporter.java:252)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.run(N5Exporter.java:420)
	at org.scijava.command.CommandModule.run(CommandModule.java:196)
	at org.scijava.module.ModuleRunner.run(ModuleRunner.java:163)
	at org.scijava.module.ModuleRunner.call(ModuleRunner.java:124)
	... 6 more

image

Export of RGB types fails

Should RGB images be written as int32 images (rgba)? or as 3-channel uint8 images? or prompt user for a choice?

Exception in thread "main" java.lang.NullPointerException
	at org.janelia.saalfeldlab.n5.DatasetAttributes.asMap(DatasetAttributes.java:103)
	at org.janelia.saalfeldlab.n5.N5Writer.setDatasetAttributes(N5Writer.java:84)
	at org.janelia.saalfeldlab.n5.N5Writer.createDataset(N5Writer.java:133)
	at org.janelia.saalfeldlab.n5.imglib2.N5Utils.save(N5Utils.java:1273)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.writeSplitChannels(N5Exporter.java:248)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.process(N5Exporter.java:205)
	at org.janelia.saalfeldlab.n5.ij.N5Exporter.run(N5Exporter.java:280)
	at org.janelia.saalfeldlab.n5.demos.runImageJBogo.main(runImageJBogo.java:70)

NullPointerException after browse

I'm getting a new NullPointerException after browsing to an n5 and opening it:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$null$10(DatasetSelectorDialog.java:620)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

The n5 I'm opening is an export output generated by https://github.com/saalfeldlab/stitching-spark

The n5 seems to load correctly in the Main tab but nothing is loaded in the other tabs. So I'm not sure if this is a real issue, because viewing seem to work okay afterwards, but the exception just seems worrisome.

Intermittent test failure

When running the pom-scijava melting pot, the n5-ij component sometimes fails tests with the exception:

java.lang.AssertionError: /cosem_ms
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.assertTrue(Assert.java:42)
	at org.junit.Assert.assertNotNull(Assert.java:713)
	at org.janelia.saalfeldlab.n5.metadata.MetadataTests.testCosemMetadataMultiscale(MetadataTests.java:58)

To work around this, I just rerun the CI build and it usually passes the next time. But it would be nice if this could be made more robust. Any ideas what might be going on here?

Conversion of datatypes not-natively supported by ImageJ

  • Convert doubles to floats.

  • Convert integer types

  • Change display of datasets needing conversion in dialog

Converting integer types

Create a converter by:

  • iterating through the whole image, creating an array of unique values
  • sort
  • linearly map range of input to full range of uint16
  • Should I map signed 8-bit integers to uint8's?

Display of datasets needing conversion

  • Red text
  • append (remap to float), or (remap to 16-bit) to dataset name in as appropriate

Opening N5 is slow

Hi, for me opening only uses a single thread more or less, which is not intended. Thus I was wondering how the LoopBuilder distributes tasks:

LoopBuilder.setImages( convImg, ipImg )
.multiThreaded( new DefaultTaskExecutor( exec ))
.forEachPixel( (x,y) -> y.set( x ));

Are maybe all processed pixels close to each other, so it wouldn't really open different blocks in parallel since all threads wait for the same block to be loaded?

Also, for virtual loading one should use multi-threading as well. ImageJFunctions.show does take a ExecutorService optionally for that ... we wrote this for BigStitcher some time ago. Because even if you load one z-plane virtually, you still need to load the entire blocks that are usually big in z.

Happy to help,
Stephan

Metadata translation progress

Keeping track of progress on metadata translations here
https://github.com/saalfeldlab/n5-ij/tree/translation-metadata

Some of this work may move to n5-imglib2

Ideas for consideration

  • implement a dataset-wise translation that does not require operating on the entire tree

TODOs

OutOfMemoryError during dataset discovery

Caused by: java.lang.OutOfMemoryError: unable to create new native thread
	at java.lang.Thread.start0(Native Method)
	at java.lang.Thread.start(Thread.java:717)
	at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:957)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1378)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer.discoverThreadsHelper(N5DatasetDiscoverer.java:141)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer.access$100(N5DatasetDiscoverer.java:51)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer$1$1.call(N5DatasetDiscoverer.java:167)
	at org.janelia.saalfeldlab.n5.N5DatasetDiscoverer$1$1.call(N5DatasetDiscoverer.java:163)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: unable to create new native thread
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog$LoaderSorterAndCallback.run(DatasetSelectorDialog.java:609)
Caused by: java.lang.OutOfMemoryError: unable to create new native thread
	at java.lang.Thread.start0(Native Method)
	at java.lang.Thread.start(Thread.java:717)

metadata parsing post n5 attribute cache

Use cases

n5-ij needs:

  • read metadata from an n5 group or dataset
  • write metadata into an n5 group or dataset
  • read metadata from an ImagePlus
  • write metadata into ImagePlus
  • Create a tree of all datasets in an n5 container down to the datasets
    • n5.deepListDatasets creates a flat list from which we can build a tree

n5-viewer additionally needs:

  • identify and open multiscale groups of datasets

@cmhulbert
what does paintera need that's not the above

Open n5's by drag+drop into Fiji

Possible behavior:

  • If there is one dataset in the container, open it immediately.
  • If there are several datasets
    • Open all datasets immediately (?)
    • Show dialog showing all datasets selected and prompt user for changes (?)

OME-Zarr containers do not parse when nested inside other paths

When using the "Open N5" dialog if I select an OME-Zarr it parses quickly and correctly:
Screenshot 2024-03-01 at 1 45 48 PM

But if I create an empty folder and put the OME-Zarr inside, and point "Open N5" to that containing folder, it gets stuck on the "Parsing..." step for several minutes and then eventually just presents the underlying directory structure:

Screenshot 2024-03-01 at 1 54 44 PM

There are no errors generated.

Unit should be "micrometer" for compatbility with OME-NGFF

When exporting with OME-NGFF metadata, the current plugin produces something like this:

{"path":"image/s0","axes":[{"type":"space","name":"x","unit":"micron"},{"type":"space","name":"y","unit":"micron"},{"type":"space","name":"z","unit":"micron"}],"coordinateTransformations":[{"scale":[0.2,0.13000001170000106,0.13000001170000106],"type":"scale"},{"translation":[0.0,0.0,0.0],"type":"translation"}]}

The unit "micron" is not recommended by the spec which instead recommends "micrometer". If this isn't possible, perhaps OME-NGFF can be petitioned to add "micron", since it is a common term and valid in UDUNITS-2.

Invalid default directories throws errors / breaks N5 dialog

Thanks to @krokicki who found this.

Need to check for invalid / faulty default directories (e.g. IJ.getDirectory("current") ) before trying to parse the container.

See:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at java.io.File.<init>(File.java:277)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openBrowseDialog(DatasetSelectorDialog.java:450)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:480)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.openContainer(DatasetSelectorDialog.java:468)
	at org.janelia.saalfeldlab.n5.ui.DatasetSelectorDialog.lambda$run$2(DatasetSelectorDialog.java:272)
	at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
	at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
	at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
	at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
	at java.awt.Component.processMouseEvent(Component.java:6539)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
	at java.awt.Component.processEvent(Component.java:6304)
	at java.awt.Container.processEvent(Container.java:2239)
	at java.awt.Component.dispatchEventImpl(Component.java:4889)
	at java.awt.Container.dispatchEventImpl(Container.java:2297)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
	at java.awt.Container.dispatchEventImpl(Container.java:2283)
	at java.awt.Window.dispatchEventImpl(Window.java:2746)
	at java.awt.Component.dispatchEvent(Component.java:4711)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
	at java.awt.EventQueue$4.run(EventQueue.java:733)
	at java.awt.EventQueue$4.run(EventQueue.java:731)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.