diff --git a/build.gradle.kts b/build.gradle.kts index beaa0871..5e8ce2c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -60,8 +60,20 @@ dependencies { implementation("net.java.dev.jna:jna-platform:5.11.0") implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-imglib2") + implementation("org.janelia.saalfeldlab:n5-zarr") + implementation("org.janelia.saalfeldlab:n5-aws-s3") + + implementation("org.embl.mobie:mobie-io:2.2.3") + implementation("org.apache.logging.log4j:log4j-api:2.20.0") implementation("org.apache.logging.log4j:log4j-1.2-api:2.20.0") + + // Dependency for AWS Java SDK + //implementation("software.amazon.awssdk:s3:2.17.174") + implementation("com.amazonaws:aws-java-sdk-s3") + + // Dependency for NetCDF-Java, if needed for Zarr handling + implementation("edu.ucar:netcdf4:5.5.1") implementation("com.formdev:flatlaf:3.3") @@ -138,7 +150,7 @@ dependencies { // OME implementation("ome:formats-bsd") - implementation("ome:formats-gpl") + // implementation("ome:formats-gpl") } //kapt { diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/LoadCryoETDataPortal.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/LoadCryoETDataPortal.kt new file mode 100644 index 00000000..05ae13c4 --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/LoadCryoETDataPortal.kt @@ -0,0 +1,156 @@ +/*- + * #%L + * Scenery-backed 3D visualization package for ImageJ. + * %% + * Copyright (C) 2016 - 2024 sciview developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package sc.iview.commands.demo.advanced + +import graphics.scenery.Origin +import graphics.scenery.volumes.Colormap +import net.imagej.lut.LUTService +import net.imagej.ops.OpService +import net.imglib2.FinalInterval +import net.imglib2.RandomAccessibleInterval +import net.imglib2.img.Img +import net.imglib2.img.array.ArrayImgs +import net.imglib2.img.cell.CellImgFactory +import net.imglib2.loops.LoopBuilder +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.integer.UnsignedByteType +import net.imglib2.type.numeric.real.FloatType +import net.imglib2.view.Views +import org.embl.mobie.io.ome.zarr.openers.OMEZarrS3Opener +import org.joml.Vector3f +import org.joml.Vector4f +import org.scijava.command.Command +import org.scijava.command.CommandService +import org.scijava.log.LogService +import org.scijava.plugin.Menu +import org.scijava.plugin.Parameter +import org.scijava.plugin.Plugin +import org.scijava.ui.UIService +import sc.iview.SciView +import sc.iview.commands.MenuWeights + +@Plugin(type = Command::class, + label = "Load CryoET Data Portal demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "Load CryoET Data Portal demo", weight = MenuWeights.DEMO_ADVANCED_CREMI)]) +class LoadCryoETDataPortal : Command { + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + private var zarrPath = "https://files.cryoetdataportal.cziscience.com/10000/TS_043/Tomograms/VoxelSpacing13.480/CanonicalTomogram/TS_043.zarr" + + /** + * When an object implementing interface `Runnable` is used + * to create a thread, starting the thread causes the object's + * `run` method to be called in that separately executing + * thread. + * + * + * The general contract of the method `run` is that it may + * take any action whatsoever. + * + * @see Thread.run + */ + + override fun run() { + val task = sciview.taskManager.newTask("CryoETDataPortal", "Loading dataset") + + task.status = "Reading dataset" + val spimData = OMEZarrS3Opener.readURL(zarrPath) + val setupId = 0 + val timepointId = 0 + val rawRaiVolume = ( + spimData.getSequenceDescription() + .getImgLoader() + .getSetupImgLoader(setupId) + .getImage(timepointId) + ) as RandomAccessibleInterval + + // Calculate half of the z-dimension + val halfZ = rawRaiVolume.dimension(2) / 2 + + // Define the interval for half of the z-axis + val minInterval = longArrayOf(0, 0, 0) + val maxInterval = longArrayOf(rawRaiVolume.dimension(0) - 1, rawRaiVolume.dimension(1) - 1, halfZ) + val halfZInterval = FinalInterval(minInterval, maxInterval) + + // Create a view over half of the z-axis + val halfZView = Views.interval(rawRaiVolume, halfZInterval) + + // Create a CellImgFactory for UnsignedByteType with a specified cell size + val cellSize = 64 + val factory = CellImgFactory(UnsignedByteType(), cellSize, cellSize, cellSize) + + // Create an empty RandomAccessibleInterval of UnsignedByteType with half z-dimension using the factory + val halfDimensions = longArrayOf(rawRaiVolume.dimension(0), rawRaiVolume.dimension(1), halfZ + 1) + val halfRaiVolume: Img = factory.create(*halfDimensions) + + + // Copy and convert the data from the view into the new RAI + LoopBuilder.setImages(halfZView as RandomAccessibleInterval, halfRaiVolume).forEachPixel { input, output -> + output.setInteger(((input.get() + 26f) / 60 * 255.0).toInt().coerceIn(0, 255)) + } + + + val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) + + val v = sciview.addVolume(halfRaiVolume, "CryoET Data Portal") { + origin = Origin.FrontBottomLeft + this.spatialOrNull()?.scale = Vector3f(1f, 1f, 1f) + // transferFunction = TransferFunction.ramp(0.3f, 0.1f, 0.1f) + // min 20, max 180, color map fire + + // transferFunction.addControlPoint(0.3f, 0.5f) + // transferFunction.addControlPoint(0.8f, 0.01f) + converterSetups.get(0).setDisplayRange(0.0, 255.0) + colormap = Colormap.fromColorTable(colormapVolume) + } + + task.completion = 100.0f + } + + companion object { + @Throws(Exception::class) + @JvmStatic + fun main(args: Array) { + val sv = SciView.create() + val command = sv.scijavaContext!!.getService(CommandService::class.java) + val argmap = HashMap() + command.run(LoadCryoETDataPortal::class.java, true, argmap) + } + } +} diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/LoadOpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/LoadOpenOrganelle.kt new file mode 100644 index 00000000..ad57974c --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/LoadOpenOrganelle.kt @@ -0,0 +1,123 @@ +/*- + * #%L + * Scenery-backed 3D visualization package for ImageJ. + * %% + * Copyright (C) 2016 - 2024 sciview developers. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package sc.iview.commands.demo.advanced + +import bdv.util.volatiles.VolatileViews +import graphics.scenery.Origin +import graphics.scenery.volumes.Colormap +import graphics.scenery.volumes.Volume +import net.imagej.lut.LUTService +import net.imagej.ops.OpService +import net.imglib2.FinalInterval +import net.imglib2.Interval +import net.imglib2.RandomAccessibleInterval +import net.imglib2.converter.Converters +import net.imglib2.img.Img +import net.imglib2.img.array.ArrayImgs +import net.imglib2.img.cell.CellImgFactory +import net.imglib2.loops.LoopBuilder +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.integer.UnsignedByteType +import net.imglib2.type.numeric.real.FloatType +import net.imglib2.type.volatiles.VolatileUnsignedByteType +import net.imglib2.view.Views +import org.embl.mobie.io.ome.zarr.openers.OMEZarrS3Opener +import org.joml.Vector3f +import org.joml.Vector4f +import org.scijava.command.Command +import org.scijava.command.CommandService +import org.scijava.log.LogService +import org.scijava.plugin.Menu +import org.scijava.plugin.Parameter +import org.scijava.plugin.Plugin +import org.scijava.ui.UIService +import sc.iview.SciView +import sc.iview.commands.MenuWeights +import net.imglib2.converter.Converter +import net.imglib2.type.numeric.integer.UnsignedIntType +import net.imglib2.type.numeric.integer.UnsignedShortType +import net.imglib2.type.volatiles.VolatileUnsignedIntType +import net.imglib2.type.volatiles.VolatileUnsignedShortType +import org.embl.mobie.io.openorganelle.OpenOrganelleS3Opener + +@Plugin(type = Command::class, + label = "Load Open Organelle demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "Load Open Organelle demo", weight = MenuWeights.DEMO_ADVANCED_CREMI)]) +class LoadOpenOrganelle : Command { + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + override fun run() { + val reader = OMEZarrS3Opener( + "https://janelia-cosem.s3.amazonaws.com", + "us-west-2", + "jrc_hela-2") + OpenOrganelleS3Opener.setLogging(true) + val image = reader.readKey("jrc_hela-2.n5/em/fibsem-uint16") + + // Assume the data is of UnsignedIntType + // + val rai = image.getSequenceDescription().getImgLoader() + + //val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) + + // Wrap the RandomAccessibleInterval with VolatileViews for tiled rendering + //val volatileRai = VolatileViews.wrapAsVolatile(rai) as RandomAccessibleInterval + + // Create and configure the volume +// val volume = Volume.fromRAI( +// rai, +// VolatileUnsignedShortType(), +// name = "My image", +// hub = sciview.hub +// ) + +// sciview.addNode(volume) + } + + companion object { + @Throws(Exception::class) + @JvmStatic + fun main(args: Array) { + val sv = SciView.create() + val command = sv.scijavaContext!!.getService(CommandService::class.java) + val argmap = HashMap() + command.run(LoadOpenOrganelle::class.java, true, argmap) + } + } +}