Skip to content

Commit

Permalink
Merge pull request #529 from saalfeldlab/feat/omengff
Browse files Browse the repository at this point in the history
feat: support OmeNgff Metadata
  • Loading branch information
cmhulbert authored May 2, 2024
2 parents df559b1 + 62fc067 commit 0737dee
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 66 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
<n5-aws-s3.version>4.1.2</n5-aws-s3.version>
<n5-zarr.version>1.3.1</n5-zarr.version>
<n5-imglib2.version>7.0.0</n5-imglib2.version>
<n5-universe.version>1.4.0</n5-universe.version>
<n5-universe.version>1.4.3</n5-universe.version>

<enforcer.skip>true</enforcer.skip>
</properties>
Expand Down Expand Up @@ -632,7 +632,7 @@
<mailingLists>
<mailingList>
<name>ImageJ Forum</name>
<archive>http://forum.imagej.net/</archive>
<archive>https://forum.image.sc/</archive>
</mailingList>
</mailingLists>

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/janelia/saalfeldlab/util/n5/N5Data.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.janelia.saalfeldlab.n5.N5Writer;
import org.janelia.saalfeldlab.n5.imglib2.N5LabelMultisets;
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SingleScaleMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata;
import org.janelia.saalfeldlab.paintera.Paintera;
import org.janelia.saalfeldlab.paintera.cache.WeakRefVolatileCache;
Expand Down Expand Up @@ -624,7 +624,7 @@ public static ImagesWithTransform<LabelMultisetType, VolatileLabelMultisetType>[
final SharedQueue queue,
final int priority) throws IOException {

SpatialMultiscaleMetadata<N5SingleScaleMetadata> metadata = metadataState.getMetadata();
SpatialMultiscaleMetadata<N5SpatialDatasetMetadata> metadata = metadataState.getMetadata();
final String[] ssPaths = metadata.getPaths();

LOG.debug("Opening groups {} as multi-scale in {} ", Arrays.toString(ssPaths), metadata.getPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import net.imglib2.realtransform.AffineGet;
import net.imglib2.realtransform.AffineTransform3D;
import org.janelia.saalfeldlab.n5.universe.metadata.N5MultiScaleMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata;

import java.util.function.Predicate;
import java.util.regex.Pattern;

public abstract class N5PainteraDataMultiScaleGroup extends N5MultiScaleMetadata {
public abstract class N5PainteraDataMultiScaleGroup extends SpatialMultiscaleMetadata<N5SpatialDatasetMetadata> {

public static final Predicate<String> SCALE_LEVEL_PREDICATE = Pattern.compile("^s\\d+$").asPredicate();
protected final N5PainteraDataMultiScaleMetadata dataGroup;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package org.janelia.saalfeldlab.util.n5.metadata;

import bdv.util.Affine3DHelpers;
import com.sun.javafx.geom.transform.Affine3D;
import net.imglib2.realtransform.AffineGet;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.realtransform.Scale3D;
import org.janelia.saalfeldlab.n5.N5Reader;
import org.janelia.saalfeldlab.n5.universe.N5TreeNode;
import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser;
import org.janelia.saalfeldlab.n5.universe.metadata.N5MultiScaleMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SingleScaleMetadata;
import org.janelia.saalfeldlab.paintera.state.metadata.SingleScaleMetadataState;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -21,14 +17,11 @@
/**
* Metadata Parser for a Paintera Data Multiscale Dataset. Namely, transforms are dependant on group metadata
*/
public class N5PainteraDataMultiScaleMetadata extends N5MultiScaleMetadata {
public class N5PainteraDataMultiScaleMetadata extends SpatialMultiscaleMetadata<N5SpatialDatasetMetadata> {

private AffineTransform3D groupTransform;

public N5PainteraDataMultiScaleMetadata(final String basePath, final N5SingleScaleMetadata[] childrenMetadata, final AffineTransform3D groupTransform) {
public N5PainteraDataMultiScaleMetadata(final String basePath, final N5SpatialDatasetMetadata[] childrenMetadata) {

super(basePath, childrenMetadata);
this.groupTransform = groupTransform;
}
@Override public String unit() {

Expand All @@ -46,7 +39,7 @@ public static class PainteraDataMultiScaleParser implements N5MetadataParser<N5P
final Map<String, N5TreeNode> scaleLevelNodes = new HashMap<>();
for (final N5TreeNode childNode : node.childrenList()) {
if (N5PainteraDataMultiScaleGroup.SCALE_LEVEL_PREDICATE.test(childNode.getNodeName()) && childNode.isDataset()
&& childNode.getMetadata() instanceof N5SingleScaleMetadata) {
&& childNode.getMetadata() instanceof N5SpatialDatasetMetadata) {
scaleLevelNodes.put(childNode.getNodeName(), childNode);
}
}
Expand Down Expand Up @@ -113,7 +106,7 @@ public static class PainteraDataMultiScaleParser implements N5MetadataParser<N5P
);
}

return Optional.of(new N5PainteraDataMultiScaleMetadata(node.getPath(), resolvedChildrenMetadata, transform));
return Optional.of(new N5PainteraDataMultiScaleMetadata(node.getPath(), resolvedChildrenMetadata));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
import org.janelia.saalfeldlab.n5.universe.metadata.N5MetadataParser;
import org.janelia.saalfeldlab.n5.universe.metadata.N5MultiScaleMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SingleScaleMetadata;
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata;

import java.io.IOException;
import java.util.Optional;

public class N5PainteraLabelMultiScaleGroup extends N5PainteraDataMultiScaleGroup {
Expand Down Expand Up @@ -146,12 +146,16 @@ public static class PainteraLabelMultiScaleParser implements N5MetadataParser<N5
final var finalFragmentSegmentAssignmentGroup = fragmentSegmentAssignment;
final var finalLabelToBlockLookupGroup = labelToBlockLookupGroup;

return Optional.ofNullable(dataGroup).map(dg -> new N5PainteraLabelMultiScaleGroup(
node.getPath(),
dg,
finalUniqueLabelsGroup, finalFragmentSegmentAssignmentGroup, finalLabelToBlockLookupGroup,
maxId, dg.getChildrenMetadata()[0].isLabelMultiset()
));
return Optional.ofNullable(dataGroup).map(dg -> {
final N5SpatialDatasetMetadata firstChild = dg.getChildrenMetadata()[0];
final Boolean isLabelMultiset = firstChild instanceof N5SingleScaleMetadata && ((N5SingleScaleMetadata)firstChild).isLabelMultiset();
return new N5PainteraLabelMultiScaleGroup(
node.getPath(),
dg,
finalUniqueLabelsGroup, finalFragmentSegmentAssignmentGroup, finalLabelToBlockLookupGroup,
maxId, isLabelMultiset
);
});
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/main/kotlin/org/janelia/saalfeldlab/paintera/Paintera.kt
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,9 @@ class Paintera : Application() {
internal var debugMode = false

@JvmStatic
val n5Factory = N5FactoryWithCache().apply { cacheAttributes(true) }
val n5Factory = N5FactoryWithCache().apply {
cacheAttributes(true)
}

private val LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ import org.janelia.saalfeldlab.n5.universe.metadata.N5Metadata
import org.janelia.saalfeldlab.n5.universe.metadata.N5SingleScaleMetadata
import org.janelia.saalfeldlab.n5.universe.metadata.N5SpatialDatasetMetadata
import org.janelia.saalfeldlab.n5.universe.metadata.SpatialMultiscaleMetadata
import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.NgffSingleScaleAxesMetadata
import org.janelia.saalfeldlab.paintera.Paintera
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataState.Companion.isLabel
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataUtils.Companion.isLabelMultiset
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataUtils.Companion.offset
import org.janelia.saalfeldlab.paintera.state.metadata.MetadataUtils.Companion.resolution
import org.janelia.saalfeldlab.util.n5.ImagesWithTransform
import org.janelia.saalfeldlab.util.n5.N5Data
import org.janelia.saalfeldlab.util.n5.N5Helpers
Expand Down Expand Up @@ -78,20 +82,20 @@ interface MetadataState {

open class SingleScaleMetadataState(
final override var n5ContainerState: N5ContainerState,
final override val metadata: N5SingleScaleMetadata
) :
MetadataState {
override var transform: AffineTransform3D = metadata.spatialTransform3d()
final override val metadata: N5SpatialDatasetMetadata
) : MetadataState {

final override var transform: AffineTransform3D = metadata.spatialTransform3d()
override var isLabelMultiset: Boolean = metadata.isLabelMultiset
override var isLabel: Boolean = isLabel(metadata.attributes.dataType) || metadata.isLabelMultiset
override var datasetAttributes: DatasetAttributes = metadata.attributes
override var minIntensity = metadata.minIntensity()
override var maxIntensity = metadata.maxIntensity()
override var resolution = metadata.pixelResolution!!
override var translation = metadata.offset!!
override var unit = metadata.unit()!!
override var resolution = metadata.resolution
override var translation = metadata.offset
override var unit: String = metadata.unit()
override var reader = n5ContainerState.reader
override val writer :N5Writer?
override val writer: N5Writer?
get() = n5ContainerState.writer

override var group = metadata.path!!
Expand Down Expand Up @@ -129,11 +133,12 @@ open class SingleScaleMetadataState(

open class MultiScaleMetadataState constructor(
override val n5ContainerState: N5ContainerState,
final override val metadata: SpatialMultiscaleMetadata<N5SingleScaleMetadata>
final override val metadata: SpatialMultiscaleMetadata<N5SpatialDatasetMetadata>
) : MetadataState by SingleScaleMetadataState(n5ContainerState, metadata[0]) {

private val highestResMetadata: N5SingleScaleMetadata = metadata[0]
override var transform: AffineTransform3D = metadata.spatialTransform3d()
private val highestResMetadata: N5SpatialDatasetMetadata = metadata[0]
final override var transform: AffineTransform3D = metadata.spatialTransform3d()
final override var isLabelMultiset: Boolean = metadata[0].isLabelMultiset
override var isLabel: Boolean = isLabel(highestResMetadata.attributes.dataType) || isLabelMultiset
override var resolution: DoubleArray = transform.run { doubleArrayOf(get(0, 0), get(1, 1), get(2, 2)) }
override var translation: DoubleArray = transform.translation
Expand Down Expand Up @@ -180,8 +185,7 @@ open class MultiScaleMetadataState constructor(
class PainteraDataMultiscaleMetadataState constructor(
n5ContainerState: N5ContainerState,
var painteraDataMultiscaleMetadata: N5PainteraDataMultiScaleGroup
) :
MultiScaleMetadataState(n5ContainerState, painteraDataMultiscaleMetadata) {
) : MultiScaleMetadataState(n5ContainerState, painteraDataMultiscaleMetadata) {

val dataMetadataState = MultiScaleMetadataState(n5ContainerState, painteraDataMultiscaleMetadata.dataGroupMetadata)

Expand All @@ -207,13 +211,33 @@ operator fun <T> SpatialMultiscaleMetadata<T>.get(index: Int): T where T : N5Spa
class MetadataUtils {

companion object {
val N5SpatialDatasetMetadata.isLabelMultiset
get() = when (this) {
is N5SingleScaleMetadata -> isLabelMultiset
else -> false
}

val N5SpatialDatasetMetadata.resolution: DoubleArray
get() = when (this) {
is N5SingleScaleMetadata -> pixelResolution!!
is NgffSingleScaleAxesMetadata -> scale
else -> DoubleArray(this.spatialTransform().numDimensions()) { 1.0 }
}

val N5SpatialDatasetMetadata.offset
get() = when (this) {
is N5SingleScaleMetadata -> offset!!
is NgffSingleScaleAxesMetadata -> translation!!
else -> DoubleArray(this.spatialTransform().numDimensions()) { 0.0 }
}

@JvmStatic
fun metadataIsValid(metadata: N5Metadata?): Boolean {
/* Valid if we are SpatialMultiscaleMetadata whose children are single scale, or we are SingleScale ourselves. */
return (metadata as? SpatialMultiscaleMetadata<*>)?.let {
it.childrenMetadata[0] is N5SingleScaleMetadata
it.childrenMetadata[0] is N5SpatialDatasetMetadata
} ?: run {
metadata is N5SingleScaleMetadata
metadata is N5SpatialDatasetMetadata
}
}

Expand All @@ -222,16 +246,16 @@ class MetadataUtils {
@Suppress("UNCHECKED_CAST")
return Optional.ofNullable(
(metadata as? N5PainteraDataMultiScaleGroup)?.let { PainteraDataMultiscaleMetadataState(n5ContainerState, it) }
?: (metadata as? SpatialMultiscaleMetadata<N5SingleScaleMetadata>)?.let { MultiScaleMetadataState(n5ContainerState, it) }
?: (metadata as? N5SingleScaleMetadata)?.let { SingleScaleMetadataState(n5ContainerState, it) }
?: (metadata as? SpatialMultiscaleMetadata<N5SpatialDatasetMetadata>)?.let { MultiScaleMetadataState(n5ContainerState, it) }
?: (metadata as? N5SpatialDatasetMetadata)?.let { SingleScaleMetadataState(n5ContainerState, it) }
)
}

@JvmStatic
fun createMetadataState(n5containerAndDataset: String): Optional<MetadataState> {

val reader = with(Paintera.n5Factory) {
openWriterOrNull(n5containerAndDataset) ?: openReaderOrNull(n5containerAndDataset)?: return Optional.empty()
val reader = with(Paintera.n5Factory) {
openWriterOrNull(n5containerAndDataset) ?: openReaderOrNull(n5containerAndDataset) ?: return Optional.empty()
}

val n5ContainerState = N5ContainerState(reader)
Expand All @@ -246,8 +270,8 @@ class MetadataUtils {

@JvmStatic
fun createMetadataState(n5container: String, dataset: String?): Optional<MetadataState> {
val reader = with(Paintera.n5Factory) {
openWriterOrNull(n5container) ?: openReaderOrNull(n5container)?: return Optional.empty()
val reader = with(Paintera.n5Factory) {
openWriterOrNull(n5container) ?: openReaderOrNull(n5container) ?: return Optional.empty()
}

val n5ContainerState = N5ContainerState(reader)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ class CreateDataset(private val currentSource: Source<*>?, vararg allSources: So
blockSize.asIntArray(),
resolution.asDoubleArray(),
offset.asDoubleArray(),
scaleLevels.stream().map { it.downsamplingFactors() }.toList().toTypedArray(),
scaleLevels.map { it.downsamplingFactors() }.toTypedArray(),
scaleLevels.stream().mapToInt { it.maxNumEntries() }.toArray()
)

Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/org/janelia/saalfeldlab/util/n5/N5Helpers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.janelia.saalfeldlab.n5.hdf5.N5HDF5Reader
import org.janelia.saalfeldlab.n5.universe.N5DatasetDiscoverer
import org.janelia.saalfeldlab.n5.universe.N5TreeNode
import org.janelia.saalfeldlab.n5.universe.metadata.*
import org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadataParser
import org.janelia.saalfeldlab.paintera.Paintera.Companion.n5Factory
import org.janelia.saalfeldlab.paintera.control.assignment.FragmentSegmentAssignmentOnlyLocal
import org.janelia.saalfeldlab.paintera.control.assignment.FragmentSegmentAssignmentOnlyLocal.NoInitialLutAvailable
Expand All @@ -50,7 +51,6 @@ import org.janelia.saalfeldlab.util.n5.universe.N5ContainerDoesntExist
import org.slf4j.LoggerFactory
import java.io.IOException
import java.lang.invoke.MethodHandles
import java.nio.file.Paths
import java.util.*
import java.util.List
import java.util.concurrent.ExecutorService
Expand Down Expand Up @@ -88,6 +88,7 @@ object N5Helpers {
private val LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

private val GROUP_PARSERS = List.of<N5MetadataParser<*>>(
OmeNgffMetadataParser(),
PainteraRawMultiScaleParser(),
PainteraLabelMultiScaleParser(),
PainteraDataMultiScaleParser(),
Expand Down
Loading

0 comments on commit 0737dee

Please sign in to comment.