Skip to content

Commit

Permalink
wip: toward a builder patter for metadata configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
bogovicj committed Oct 2, 2024
1 parent 2ff3c9a commit 419ac15
Show file tree
Hide file tree
Showing 12 changed files with 857 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.janelia.saalfeldlab.n5.config;

import org.janelia.saalfeldlab.n5.metadata.MetadataHierarchyWriter;

public abstract class AbstractConfigurationBuilder implements ConfigurationBuilder {

protected Parameters parameters;

public AbstractConfigurationBuilder() {

parameters = new Parameters();
}

@Override
public Parameters getParameters() {

return parameters;
}

@Override
public abstract MetadataHierarchyWriter getWriter();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package org.janelia.saalfeldlab.n5.config;

import java.util.Map;
import java.util.function.IntFunction;
import java.util.stream.IntStream;

import org.janelia.saalfeldlab.n5.Compression;
import org.janelia.saalfeldlab.n5.DataType;
import org.janelia.saalfeldlab.n5.DatasetAttributes;
import org.janelia.saalfeldlab.n5.N5Exception;
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
import org.janelia.saalfeldlab.n5.metadata.MetadataHierarchyWriter;
import org.janelia.saalfeldlab.n5.universe.metadata.axes.Axis;

import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.cell.AbstractCellImg;
import net.imglib2.img.cell.CellImg;
import net.imglib2.type.NativeType;

public interface ConfigurationBuilder {

public Parameters getParameters();

public MetadataHierarchyWriter getWriter();

public default ConfigurationBuilder image(
final RandomAccessibleInterval<? extends NativeType<?>> img,
final Axis[] axes) {

dataType((NativeType<?>)img.getType());
dimensions(img.dimensionsAsLongArray());
numChannels(img, axes);
numTimepoints(img, axes);

if (img instanceof CellImg) {
AbstractCellImg<?, ?, ?, ?> cellimg = (AbstractCellImg<?, ?, ?, ?>)img;
blockSize(cellimg.getCellGrid().getCellDimensions());
}

return this;
}

public default ConfigurationBuilder dimensions(final long... dimensions) {

getParameters().dimensions = dimensions;
return this;
}

public default ConfigurationBuilder blockSize(final int... blockSize) {

getParameters().blockSize = blockSize;
return this;
}

public default ConfigurationBuilder dataType(final DataType dataType ) {

getParameters().dataType = dataType;
return this;
}

public default ConfigurationBuilder dataType(@SuppressWarnings("rawtypes") final NativeType type ) {

@SuppressWarnings("unchecked")
final DataType dtype = N5Utils.dataType(type);
if (dtype != null)
dataType(dtype);

return this;
}

public default ConfigurationBuilder compression(final Compression compression ) {

getParameters().compression = compression;
return this;
}

public default ConfigurationBuilder resolution(final double... resolution) {

getParameters().resolution = resolution;
return this;
}

public default ConfigurationBuilder offset(final double... offset) {

getParameters().offset = offset;
return this;
}

public default ConfigurationBuilder unit(final String... units) {

getParameters().units = units;
return this;
}

public default ConfigurationBuilder numChannels(final int numChannels) {

getParameters().numChannels = numChannels;
return this;
}

public default ConfigurationBuilder multichannelGroups(final IntFunction<String> relativeChannelGroupName) {

getParameters().relativeChannelGroupName = relativeChannelGroupName;
return this;
}

public default ConfigurationBuilder multichannelGroups(final String... relativeChannelGroupNames) {

getParameters().relativeChannelGroupName = c -> relativeChannelGroupNames[c];
return this;
}

public default ConfigurationBuilder multichannelGroups(final Map<Integer,String> relativeChannelGroupNames) {

getParameters().relativeChannelGroupName = c -> relativeChannelGroupNames.get(c);
return this;
}

public default ConfigurationBuilder numScales(final int numScales) {

getParameters().numScales = numScales;
return this;
}

public default ConfigurationBuilder multiscaleGroups(final IntFunction<String> relativeScaleLevelGroupName) {

getParameters().relativeScaleLevelGroupName = relativeScaleLevelGroupName;
return this;
}

public default ConfigurationBuilder multiscaleGroups(final String... relativeScaleLevelGroupName) {

getParameters().relativeScaleLevelGroupName = c -> relativeScaleLevelGroupName[c];
return this;
}

public default ConfigurationBuilder multiscaleGroups(final Map<Integer, String> relativeScaleLevelGroupName) {

getParameters().relativeScaleLevelGroupName = s -> relativeScaleLevelGroupName.get(s);
return this;
}

public default ConfigurationBuilder downsampleFactors(IntFunction<int[]> downsamplingFactors) {

getParameters().downsamplingFactors = downsamplingFactors;
return this;
}

public default ConfigurationBuilder downsampleFactors(int[][] downsamplingFactors) {

getParameters().numScales = downsamplingFactors.length;
getParameters().downsamplingFactors = s -> downsamplingFactors[s];
return this;
}

public default DatasetAttributes getBaseDatasetAttributes() {

return new DatasetAttributes(
getParameters().dimensions,
getParameters().blockSize,
getParameters().dataType,
getParameters().compression);
}

public static long numChannels(final RandomAccessibleInterval<? extends NativeType<?>> img, final Axis[] axes) {

return countElementsOfType(img, axes, Axis.CHANNEL);
}

public static long numTimepoints(final RandomAccessibleInterval<? extends NativeType<?>> img, final Axis[] axes) {

return countElementsOfType(img, axes, Axis.SPACE);
}

public static long countElementsOfType(final RandomAccessibleInterval<? extends NativeType<?>> img, final Axis[] axes, final String type) {

final int[] indexes = IntStream.range(0, axes.length)
.filter(i -> axes[i].getType().equals(type))
.toArray();
if (indexes.length == 1)
throw new N5Exception(String.format("Multiple %s axes detected, but only one allowed", type));
else if (indexes.length == 1)
return img.dimension(indexes[0]);
else
return 1;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.janelia.saalfeldlab.n5.config;

import org.janelia.saalfeldlab.n5.N5Exception;
import org.janelia.saalfeldlab.n5.metadata.N5ViewerMultiscaleHierarchyWriter;
import org.janelia.saalfeldlab.n5.universe.metadata.axes.AxisUtils;

import net.imglib2.img.cell.CellImgFactory;
import net.imglib2.type.numeric.integer.UnsignedByteType;

public class N5ViewerBuilder extends AbstractConfigurationBuilder {

public N5ViewerBuilder() {

super();
}

@Override
public N5ViewerMultiscaleHierarchyWriter getWriter() {

// TODO check that all units are equal?
return N5ViewerMultiscaleHierarchyWriter.build(
getParameters().numChannels,
getBaseDatasetAttributes(),
getParameters().numScales,
getParameters().resolution,
getParameters().units[0],
getParameters().downsamplingFactors);
}

@Override
public ConfigurationBuilder offset(final double[] offset) {

throw new N5Exception("N5Viewer does not support offset");
}

public static void main(String[] args) {

final N5ViewerBuilder builder = new N5ViewerBuilder();
builder.image(
new CellImgFactory<UnsignedByteType>(new UnsignedByteType()).create(4, 3, 2),
AxisUtils.buildAxes("x", "y", "z"));
System.out.println(builder.parameters);

// throws exception
// builder.offset(new double[]{2, 3, 4});
}

}
51 changes: 51 additions & 0 deletions src/main/java/org/janelia/saalfeldlab/n5/config/Parameters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.janelia.saalfeldlab.n5.config;

import java.util.Arrays;
import java.util.function.IntFunction;

import org.janelia.saalfeldlab.n5.Compression;
import org.janelia.saalfeldlab.n5.DataType;
import org.janelia.saalfeldlab.n5.GzipCompression;

public class Parameters {

// single (base) dataset
public long[] dimensions;
public int[] blockSize;
public DataType dataType;
public Compression compression = new GzipCompression();

// spatial and time resolution
public double[] resolution;
public double[] offset;
public String[] units;

// multichannel
public int numChannels = 1;
public IntFunction<String> relativeChannelGroupName = c -> String.format("c%d", c);

// multiscale
public int numScales;
public IntFunction<String> relativeScaleLevelGroupName = s -> String.format("s%d", s);
public IntFunction<int[]> blockSizePerScaleLevel = s -> blockSize;
public IntFunction<int[]> downsamplingFactors = s -> {
final int[] factors = new int[dimensions.length];
Arrays.fill(factors, (int)Math.pow(2, s));
return factors;
};

public String toString() {

return String.format(
"dimensions : %s\n" +
"dataType : %s\n" +
"blockSize : %s\n" +
"resolution : %s\n" +
"offset : %s\n",
Arrays.toString(dimensions),
dataType,
Arrays.toString(blockSize),
Arrays.toString(resolution),
Arrays.toString(offset));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.janelia.saalfeldlab.n5.metadata;

import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.stream.IntStream;

import org.janelia.saalfeldlab.n5.Compression;
import org.janelia.saalfeldlab.n5.DatasetAttributes;
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
import org.janelia.scicomp.n5.zstandard.ZstandardCompression;

import net.imglib2.RandomAccessibleInterval;
import net.imglib2.type.NativeType;

public class DatasetUtils {

public static <T extends NativeType<T>> DatasetAttributes defaultDatasetAttributes(
final RandomAccessibleInterval<T> img ) {

return datasetAttributes(img,
() -> IntStream.generate(() -> 64).limit(img.numDimensions()).toArray(),
ZstandardCompression::new);
}

public static <T extends NativeType<T>> DatasetAttributes datasetAttributes(
final RandomAccessibleInterval<T> img,
final Supplier<int[]> blockSize,
final Supplier<Compression> compression) {

return new DatasetAttributes(
img.dimensionsAsLongArray(),
blockSize.get(),
N5Utils.dataType(img.getType()),
compression.get());
}

public static IntFunction<int[]> toFunction(int[][] arr) {

return i -> arr[i];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.janelia.saalfeldlab.n5.metadata;

import org.janelia.saalfeldlab.n5.N5Writer;

public interface MetadataHierarchyWriter {

public void write(final N5Writer n5, final String baseDataset);

}
Loading

0 comments on commit 419ac15

Please sign in to comment.