From f4bfc8e54070a9e6c35d30f9aef1b7ae036d7e39 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Tue, 13 Jun 2023 07:01:20 -0400 Subject: [PATCH 01/29] [wip] OpenOrganelle demo, super not working yet --- build.gradle.kts | 8 + .../kotlin/sc/iview/commands/MenuWeights.kt | 1 + .../commands/demo/advanced/OpenOrganelle.kt | 256 ++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/build.gradle.kts b/build.gradle.kts index b058fa79..b79099e5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -103,6 +103,14 @@ dependencies { // implementation(n5.imglib2) implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-hdf5") + implementation("org.janelia.saalfeldlab:n5-ij:3.2.4-SNAPSHOT") + implementation("org.janelia.saalfeldlab:n5-imglib2:5.0.0") + implementation("org.janelia.saalfeldlab:n5-viewer_fiji:5.3.0") + //implementation("com.github.saalfeldlab:n5-viewer:ec0b177") + implementation("org.janelia.saalfeldlab:n5-aws-s3") + implementation("org.janelia.saalfeldlab:n5-google-cloud") + implementation("org.janelia.saalfeldlab:n5-blosc") + implementation("org.janelia.saalfeldlab:n5-zarr") implementation("sc.fiji:spim_data") implementation(platform(kotlin("bom"))) diff --git a/src/main/kotlin/sc/iview/commands/MenuWeights.kt b/src/main/kotlin/sc/iview/commands/MenuWeights.kt index fa91c6e4..43921ddb 100644 --- a/src/main/kotlin/sc/iview/commands/MenuWeights.kt +++ b/src/main/kotlin/sc/iview/commands/MenuWeights.kt @@ -112,6 +112,7 @@ object MenuWeights { const val DEMO_ADVANCED_CREMI = 1.0 const val DEMO_ADVANCED_BDVSLICING = 2.0 const val DEMO_ADVANCED_MESHTEXTURE = 3.0 + const val DEMO_ADVANCED_OPENORGANELLE = 4.0 // Help const val HELP_HELP = 0.0 const val HELP_ABOUT = 200.0 diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt new file mode 100644 index 00000000..da14037a --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt @@ -0,0 +1,256 @@ +package sc.iview.commands.demo.advanced + +import graphics.scenery.Origin +import graphics.scenery.utils.extensions.xyz +import graphics.scenery.volumes.Colormap +import graphics.scenery.volumes.TransferFunction +import net.imagej.lut.LUTService +import net.imagej.mesh.Mesh +import net.imagej.mesh.Meshes +import net.imagej.ops.OpService +import net.imglib2.RandomAccessibleInterval +import net.imglib2.cache.img.CachedCellImg +import net.imglib2.roi.labeling.ImgLabeling +import net.imglib2.roi.labeling.LabelRegions +import net.imglib2.type.NativeType +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.RealType +import net.imglib2.view.Views +import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer +import org.janelia.saalfeldlab.n5.N5Reader +import org.janelia.saalfeldlab.n5.N5TreeNode +import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets +import org.janelia.saalfeldlab.n5.ij.N5Factory +import org.janelia.saalfeldlab.n5.ij.N5Importer +import org.janelia.saalfeldlab.n5.imglib2.N5Utils +import org.janelia.saalfeldlab.n5.metadata.* +import org.janelia.saalfeldlab.n5.ui.DataSelection +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 sc.iview.commands.demo.basic.VolumeRenderDemo +import sc.iview.process.MeshConverter +import java.io.File +import java.io.IOException +import java.util.* +import java.util.concurrent.Executors + + +@Plugin(type = Command::class, + label = "OpenOrganelle demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) +class OpenOrganelle : Command { + @Parameter + private lateinit var ui: UIService + + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var ops: OpService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + /* + * TODO + * + * https://openorganelle.janelia.org/datasets/jrc_mus-kidney + * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 + * + */ + + internal class DefaultLabelIterator : MutableIterator { + private var i = 0L + override fun hasNext(): Boolean { + return i < Long.MAX_VALUE + } + + override fun next(): Long { + return i++ + } + + override fun remove() { + throw UnsupportedOperationException() + } + } + + /** + * 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("OpenOrganelle", "Loading dataset") + + val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") + + // Read the EM volume + task.status = "Reading image volume" + //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") + log.info("Start Reading") + val nai = readMultiscaleN5() + + log.info("Done Reading") + + if (nai == null) { + log.error("Could not read data") + return + } +// val raiVolume = nai.third +// val cursor = Views.iterable(raiVolume).localizingCursor() +// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { +// cursor.fwd() +// cursor.get().set(0) +// } +// + val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) +// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) + +// sciview.addVolume(nai) { +// origin = Origin.FrontBottomLeft +// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) +// 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(20.0, 220.0) +// colormap = Colormap.fromColorTable(colormapVolume) +// } + + // Read the labels volume + task.status = "Reading labels volume" + val labels = readMultiscaleN5() + + task.status = "Creating labeling" + task.completion = 10.0f +// val rai = nai.second +// log.info("Got ${nai.first.size} labels") + + // let's extract some neurons here + log.info("Creating labeling ...") + + //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() +// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) +// log.info("Creating regions...") +// val regions = LabelRegions(labeling) +// log.info("Created ${regions.count()} regions") +// +// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } +// +// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") +// +// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> +// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") +// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" +// +// // ui.show(region) +// // Generate the mesh with imagej-ops +// val m: Mesh = Meshes.marchingCubes(region); +// +// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") +// // Convert the mesh into a scenery mesh for visualization +// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) +// sciview.addNode(mesh) { +// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) +// ifMaterial { +// diffuse = +// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() +// .xyz() +// roughness = 0.0f +// } +// name = "Neuron $i" +// } +// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f +// task.completion = completion +// } +// +// task.completion = 100.0f + } + + + + fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", + multiscaleBaseDataset: String = "/labels/empanada-mito_seg", + scale: Double = 1.0): CachedCellImg, *>? { + // set up the n5 reader + + log.info("Opening reader") + var n5: N5Reader = N5Factory().openReader(n5root) + // parse the metadata so bdv knows how to display the scales + val importers = Arrays.asList>(*N5Importer.PARSERS) + val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) + log.info("Dataset discoverer") + val parsers = N5DatasetDiscoverer( + n5, + Executors.newSingleThreadExecutor(), + importers, + groupParsers + ) + + log.info("Dataset discoverer done") + + // get the particular metadata we care above + var root = parsers.discoverAndParseRecursive("") + val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata + + var datasetToOpen = multiscaleMetadata.path + + log.info("Opening image") + + var img = N5Utils.openVolatile(n5, datasetToOpen) + + log.info("Image opened") + + // run n5 viewer + //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); + + + return img + } + + + private fun Int.toRGBColor(): Vector4f { + val a = ARGBType.alpha(this) / 255.0f + val r = ARGBType.red(this) / 255.0f + val g = ARGBType.green(this) / 255.0f + val b = ARGBType.blue(this) / 255.0f + + return Vector4f(r, g, b, a) + } + + + 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(OpenOrganelle::class.java, true, argmap) + } + } +} \ No newline at end of file From 8eb98af9fc713e66ef230c4e8eba903be2c6f382 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 15:01:19 +0200 Subject: [PATCH 02/29] Gradle: Bump scenery to 0.9.0, pom-scijava to 35.1.1, fix snakeyaml to 1.33 --- build.gradle.kts | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b0ab7430..996f56db 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ import java.net.URL import sciview.* plugins { - val ktVersion = "1.8.20" + val ktVersion = "1.8.22" val dokkaVersion = "1.8.20" java @@ -25,43 +25,48 @@ java { } repositories { + if(project.properties["useMavenLocal"] == "true") { + logger.warn("Using local Maven repository as source") + mavenLocal() + } mavenCentral() + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1221") maven("https://maven.scijava.org/content/groups/public") } dependencies { - val ktVersion = "1.8.20" - implementation(platform("org.scijava:pom-scijava:31.1.0")) + val ktVersion = "1.8.22" + implementation(platform("org.scijava:pom-scijava:35.1.1")) // Graphics dependencies - annotationProcessor("org.scijava:scijava-common:2.90.0") - kapt("org.scijava:scijava-common:2.90.0") { // MANUAL version increment + // Attention! Manual version increment necessary here! + val scijavaCommonVersion = "2.94.1" + annotationProcessor("org.scijava:scijava-common:$scijavaCommonVersion") + kapt("org.scijava:scijava-common:$scijavaCommonVersion") { exclude("org.lwjgl") } - val sceneryVersion = "0.8.0" + val sceneryVersion = "0.9.0" api("graphics.scenery:scenery:$sceneryVersion") { version { strictly(sceneryVersion) } exclude("org.biojava.thirdparty", "forester") exclude("null", "unspecified") } - implementation("com.fasterxml.jackson.core:jackson-databind:2.13.4.2") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.4") - implementation("org.msgpack:jackson-dataformat-msgpack:0.9.3") implementation("net.java.dev.jna:jna-platform:5.11.0") - implementation("net.clearvolume:cleargl") implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-imglib2") implementation("org.apache.logging.log4j:log4j-api:2.20.0") implementation("org.apache.logging.log4j:log4j-1.2-api:2.20.0") - implementation("com.formdev:flatlaf:2.6") + implementation("com.formdev:flatlaf") // SciJava dependencies + implementation("org.yaml:snakeyaml") { + version { strictly("1.33") } + } implementation("org.scijava:scijava-common") implementation("org.scijava:ui-behaviour") implementation("org.scijava:script-editor") @@ -435,5 +440,7 @@ artifacts { archives(dokkaHtmlJar) } + + java.withSourcesJar() From 174e8cbb1eabb9bca8618c822d548ac7833a8aee Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 15:01:57 +0200 Subject: [PATCH 03/29] Adjust for changed APIs in scenery 0.9.0 --- .../commands/demo/animation/SceneRiggingDemo.java | 2 +- .../commands/edit/add/AddOrientationCompass.java | 2 +- src/main/java/sc/iview/io/N5IO.java | 2 +- src/main/kotlin/sc/iview/SciView.kt | 8 +++----- src/test/java/sc/iview/SciViewTest.java | 11 +++++------ 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java b/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java index 853a17e1..bfc506f9 100644 --- a/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java +++ b/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java @@ -113,7 +113,7 @@ public void run() { sciView.centerOnNode( sciView.getActiveNode() ); for( PointLight light : sciView.getLights() ) { - Icosphere s = new Icosphere(1f, 1); + Icosphere s = new Icosphere(1f, 1, false); s.getMaterial().setDiffuse(light.getEmissionColor()); s.getMaterial().setAmbient(light.getEmissionColor()); s.getMaterial().setSpecular(light.getEmissionColor()); diff --git a/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java b/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java index da8de582..ebbefe0f 100644 --- a/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java +++ b/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java @@ -86,7 +86,7 @@ private Node makeAxis( float axisLength, float angleX, float angleY, float angle return null; }); - Icosphere axisCap = new Icosphere(AXESBARRADIUS, 2); + Icosphere axisCap = new Icosphere(AXESBARRADIUS, 2, false); axisCap.ifSpatial(spatial -> { spatial.setPosition(new Vector3f(0, axisLength, 0)); return null; diff --git a/src/main/java/sc/iview/io/N5IO.java b/src/main/java/sc/iview/io/N5IO.java index e7f44569..1c8407c2 100644 --- a/src/main/java/sc/iview/io/N5IO.java +++ b/src/main/java/sc/iview/io/N5IO.java @@ -29,6 +29,7 @@ package sc.iview.io; import bdv.util.AxisOrder; +import bvv.core.VolumeViewerOptions; import graphics.scenery.Group; import graphics.scenery.Node; import graphics.scenery.primitives.PointCloud; @@ -46,7 +47,6 @@ import sc.iview.SciView; import sc.iview.SciViewService; import sc.iview.process.MeshConverter; -import tpietzsch.example2.VolumeViewerOptions; import java.io.File; import java.io.IOException; diff --git a/src/main/kotlin/sc/iview/SciView.kt b/src/main/kotlin/sc/iview/SciView.kt index 3c404ebf..19cd7102 100644 --- a/src/main/kotlin/sc/iview/SciView.kt +++ b/src/main/kotlin/sc/iview/SciView.kt @@ -37,11 +37,11 @@ import bdv.util.RandomAccessibleIntervalSource4D import bdv.util.volatiles.VolatileView import bdv.viewer.Source import bdv.viewer.SourceAndConverter +import bvv.core.VolumeViewerOptions import dev.dirs.ProjectDirectories import graphics.scenery.* import graphics.scenery.Scene.RaycastResult import graphics.scenery.backends.Renderer -import graphics.scenery.backends.opengl.OpenGLRenderer import graphics.scenery.backends.vulkan.VulkanRenderer import graphics.scenery.controls.InputHandler import graphics.scenery.controls.OpenVRHMD @@ -110,7 +110,6 @@ import sc.iview.ui.CustomPropertyUI import sc.iview.ui.MainWindow import sc.iview.ui.SwingMainWindow import sc.iview.ui.TaskManager -import tpietzsch.example2.VolumeViewerOptions import java.awt.event.WindowListener import java.io.IOException import java.net.URL @@ -388,10 +387,9 @@ class SciView : SceneryBase, CalibratedRealInterval { versionString = versionString.substring(0, 5) val launcherVersion = Version(versionString) val nonWorkingVersion = Version("4.0.5") - if (launcherVersion.compareTo(nonWorkingVersion) <= 0 + if (launcherVersion <= nonWorkingVersion && !java.lang.Boolean.parseBoolean(System.getProperty("sciview.DisableLauncherVersionCheck", "false"))) { - logger.info("imagej-launcher version smaller or equal to non-working version ($versionString vs. 4.0.5), disabling Vulkan as rendering backend. Disable check by setting 'scenery.DisableLauncherVersionCheck' system property to 'true'.") - System.setProperty("scenery.Renderer", "OpenGLRenderer") + throw IllegalStateException("imagej-launcher version is outdated, please update your Fiji installation.") } else { logger.info("imagej-launcher version bigger that non-working version ($versionString vs. 4.0.5), all good.") } diff --git a/src/test/java/sc/iview/SciViewTest.java b/src/test/java/sc/iview/SciViewTest.java index 96f0d7b6..6166ba4e 100644 --- a/src/test/java/sc/iview/SciViewTest.java +++ b/src/test/java/sc/iview/SciViewTest.java @@ -28,9 +28,10 @@ */ package sc.iview; -import cleargl.GLVector; -import graphics.scenery.*; -import graphics.scenery.attribute.material.Material; +import graphics.scenery.Group; +import graphics.scenery.Node; +import graphics.scenery.SceneryBase; +import graphics.scenery.Sphere; import io.scif.SCIFIOService; import net.imagej.ImageJService; import org.joml.Vector3f; @@ -38,8 +39,6 @@ import org.scijava.Context; import org.scijava.service.SciJavaService; import org.scijava.thread.ThreadService; -import sc.iview.SciView; -import sc.iview.SciViewService; public class SciViewTest { @@ -77,7 +76,7 @@ public void nestedNodeDeletionTest() throws Exception { Group group = new Group(); - final Sphere sphere = new Sphere( 1, 20 ); + final Sphere sphere = new Sphere( 1, 20, false ); sphere.ifMaterial( material -> { material.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) ); material.setDiffuse( new Vector3f( 1.0f, 0.0f, 0.0f ) ); From 370c8dab95cac62e7b8ee4f6ffd493a7b367b198 Mon Sep 17 00:00:00 2001 From: Samuel Pantze <83579186+smlpt@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:29:53 +0200 Subject: [PATCH 04/29] SwingSwapchain/REPLPane: Do UI initialisation on EDT, initialise REPL asynchronously --- src/main/java/sc/iview/ui/REPLPane.java | 4 +- .../kotlin/sc/iview/ui/SwingMainWindow.kt | 396 +++++++++--------- 2 files changed, 206 insertions(+), 194 deletions(-) diff --git a/src/main/java/sc/iview/ui/REPLPane.java b/src/main/java/sc/iview/ui/REPLPane.java index 76376259..ae617426 100644 --- a/src/main/java/sc/iview/ui/REPLPane.java +++ b/src/main/java/sc/iview/ui/REPLPane.java @@ -75,7 +75,7 @@ public REPLPane(final Context context) { final JScrollPane outputScroll = new JScrollPane(output); outputScroll.setPreferredSize(new Dimension(440, 400)); - repl = new ScriptREPL(context, output.getOutputStream()); + repl = new ScriptREPL(context, "Python (Jython)", output.getOutputStream()); repl.initialize(); final Writer writer = output.getOutputWriter(); @@ -89,7 +89,7 @@ public REPLPane(final Context context) { //prompt = new REPLEditor(repl, vars, output); prompt = new REPLEditor(repl, null, output); context.inject(prompt); - prompt.setREPLLanguage("Python"); + final JScrollPane promptScroll = new JScrollPane(prompt); final JPanel bottomPane = new JPanel(); diff --git a/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt b/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt index 1404b555..2faf5037 100644 --- a/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt +++ b/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt @@ -46,6 +46,7 @@ import java.awt.event.* import java.util.* import javax.script.ScriptException import javax.swing.* +import kotlin.concurrent.thread import kotlin.math.roundToInt /** @@ -58,228 +59,239 @@ class SwingMainWindow(val sciview: SciView) : MainWindow { private val logger by lazyLogger() private var previousSidebarPosition = 0 - var sceneryJPanel: SceneryJPanel + lateinit var sceneryJPanel: SceneryJPanel private set - var mainSplitPane: JSplitPane + lateinit var mainSplitPane: JSplitPane protected set - var inspector: JSplitPane + lateinit var inspector: JSplitPane protected set - var interpreterPane: REPLPane + lateinit var interpreterPane: REPLPane protected set - var nodePropertyEditor: SwingNodePropertyEditor + lateinit var nodePropertyEditor: SwingNodePropertyEditor protected set - var frame: JFrame + lateinit var frame: JFrame protected set var sidebarOpen = false protected set - private var splashLabel: SplashLabel + private lateinit var splashLabel: SplashLabel private var defaultSidebarAction: (() -> Any)? = null init { - FlatLightLaf.setup() - try { - UIManager.setLookAndFeel(FlatLightLaf()) - } catch (ex: Exception) { - System.err.println("Failed to initialize Flat Light LaF, falling back to Swing default.") - } + val initializer = Runnable { + FlatLightLaf.setup() + try { + UIManager.setLookAndFeel(FlatLightLaf()) + } catch (ex: Exception) { + System.err.println("Failed to initialize Flat Light LaF, falling back to Swing default.") + } - var x: Int - var y: Int - try { - val screenSize = Toolkit.getDefaultToolkit().screenSize - x = screenSize.width / 2 - sciview.windowWidth / 2 - y = screenSize.height / 2 - sciview.windowHeight / 2 - } catch (e: HeadlessException) { - x = 10 - y = 10 - } + var x: Int + var y: Int + try { + val screenSize = Toolkit.getDefaultToolkit().screenSize + x = screenSize.width / 2 - sciview.windowWidth / 2 + y = screenSize.height / 2 - sciview.windowHeight / 2 + } catch (e: HeadlessException) { + x = 10 + y = 10 + } - frame = JFrame("sciview") - frame.layout = BorderLayout(0, 0) - frame.setSize(sciview.windowWidth, sciview.windowHeight) - frame.setLocation(x, y) - - splashLabel = SplashLabel() - val glassPane = frame.glassPane as JPanel - glassPane.isVisible = true - glassPane.layout = BorderLayout() - glassPane.isOpaque = false - glassPane.add(splashLabel, BorderLayout.CENTER) - glassPane.requestFocusInWindow() - glassPane.revalidate() - - frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE - nodePropertyEditor = SwingNodePropertyEditor(sciview) - - sceneryJPanel = SceneryJPanel() - JPopupMenu.setDefaultLightWeightPopupEnabled(false) - val swingMenuBar = JMenuBar() - val menus = sciview.scijavaContext?.getService(MenuService::class.java) ?: throw IllegalStateException("MenuService not available") - SwingJMenuBarCreator().createMenus(menus.getMenu("SciView"), swingMenuBar) - - val bar = ProgressPie() - bar.value = 0.0 - bar.minimumSize = Dimension(30, 30) - bar.maximumSize = Dimension(30, 30) - bar.preferredSize = Dimension(30, 30) - val progressLabel = JLabel("") - progressLabel.horizontalAlignment = SwingConstants.RIGHT - swingMenuBar.add(Box.createHorizontalGlue()) - swingMenuBar.add(progressLabel) - swingMenuBar.add(bar) - frame.jMenuBar = swingMenuBar - - sciview.taskManager.update = { current -> - if(current != null) { - progressLabel.text = "${current.source}: ${current.status} " - bar.value = current.completion.toDouble() - } else { - progressLabel.text = "" - bar.value = 0.0 + frame = JFrame("sciview") + frame.layout = BorderLayout(0, 0) + frame.setSize(sciview.windowWidth, sciview.windowHeight) + frame.setLocation(x, y) + + splashLabel = SplashLabel() + val glassPane = frame.glassPane as JPanel + glassPane.isVisible = true + glassPane.layout = BorderLayout() + glassPane.isOpaque = false + glassPane.add(splashLabel, BorderLayout.CENTER) + glassPane.requestFocusInWindow() + glassPane.revalidate() + + frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE + nodePropertyEditor = SwingNodePropertyEditor(sciview) + + sceneryJPanel = SceneryJPanel() + JPopupMenu.setDefaultLightWeightPopupEnabled(false) + val swingMenuBar = JMenuBar() + val menus = sciview.scijavaContext?.getService(MenuService::class.java) + ?: throw IllegalStateException("MenuService not available") + SwingJMenuBarCreator().createMenus(menus.getMenu("SciView"), swingMenuBar) + + val bar = ProgressPie() + bar.value = 0.0 + bar.minimumSize = Dimension(30, 30) + bar.maximumSize = Dimension(30, 30) + bar.preferredSize = Dimension(30, 30) + val progressLabel = JLabel("") + progressLabel.horizontalAlignment = SwingConstants.RIGHT + swingMenuBar.add(Box.createHorizontalGlue()) + swingMenuBar.add(progressLabel) + swingMenuBar.add(bar) + frame.jMenuBar = swingMenuBar + + sciview.taskManager.update = { current -> + if (current != null) { + progressLabel.text = "${current.source}: ${current.status} " + bar.value = current.completion.toDouble() + } else { + progressLabel.text = "" + bar.value = 0.0 + } + + bar.repaint() + } + sceneryJPanel.isVisible = true + nodePropertyEditor.component // Initialize node property panel + + val inspectorTree = nodePropertyEditor.tree + inspectorTree.toggleClickCount = 0 // This disables expanding menus on double click + val inspectorProperties = nodePropertyEditor.props + + val container = JPanel(CardLayout()) + + var propsPane = JScrollPane(inspectorProperties) + var treePane = JScrollPane(inspectorTree) + propsPane.verticalScrollBar.unitIncrement = 16 + treePane.verticalScrollBar.unitIncrement = 16 + inspector = JSplitPane(JSplitPane.VERTICAL_SPLIT, // + treePane, + propsPane) + inspector.dividerLocation = sciview.windowHeight / 3 + inspector.isContinuousLayout = true + inspector.border = BorderFactory.createEmptyBorder() + inspector.dividerSize = 4 + inspector.name = "Inspector" + container.add(inspector, "Inspector") + + // We need to get the surface scale here before initialising scenery's renderer, as + // the information is needed already at initialisation time. + val dt = frame.graphicsConfiguration.defaultTransform + val surfaceScale = Vector2f(dt.scaleX.toFloat(), dt.scaleY.toFloat()) + sciview.getScenerySettings().set("Renderer.SurfaceScale", surfaceScale) + interpreterPane = REPLPane(sciview.scijavaContext) + interpreterPane.component.border = BorderFactory.createEmptyBorder() + interpreterPane.component.name = "REPL" + container.add(interpreterPane.component, "REPL") + thread { + initializeInterpreter() } + mainSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + sceneryJPanel, + container + ) + mainSplitPane.dividerLocation = frame.width + mainSplitPane.border = BorderFactory.createEmptyBorder() + mainSplitPane.dividerSize = 4 + mainSplitPane.resizeWeight = 1.0 + mainSplitPane.rightComponent = null - bar.repaint() - } - sceneryJPanel.isVisible = true - nodePropertyEditor.component // Initialize node property panel - - val inspectorTree = nodePropertyEditor.tree - inspectorTree.toggleClickCount = 0 // This disables expanding menus on double click - val inspectorProperties = nodePropertyEditor.props - - val container = JPanel(CardLayout()) - - var propsPane = JScrollPane(inspectorProperties) - var treePane = JScrollPane(inspectorTree) - propsPane.verticalScrollBar.unitIncrement = 16 - treePane.verticalScrollBar.unitIncrement = 16 - inspector = JSplitPane(JSplitPane.VERTICAL_SPLIT, // - treePane, - propsPane) - inspector.dividerLocation = sciview.windowHeight / 3 - inspector.isContinuousLayout = true - inspector.border = BorderFactory.createEmptyBorder() - inspector.dividerSize = 1 - inspector.name = "Inspector" - container.add(inspector, "Inspector") - - // We need to get the surface scale here before initialising scenery's renderer, as - // the information is needed already at initialisation time. - val dt = frame.graphicsConfiguration.defaultTransform - val surfaceScale = Vector2f(dt.scaleX.toFloat(), dt.scaleY.toFloat()) - sciview.getScenerySettings().set("Renderer.SurfaceScale", surfaceScale) - interpreterPane = REPLPane(sciview.scijavaContext) - interpreterPane.component.border = BorderFactory.createEmptyBorder() - interpreterPane.component.name = "REPL" - container.add(interpreterPane.component, "REPL") - initializeInterpreter() - mainSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - sceneryJPanel, - container - ) - mainSplitPane.dividerLocation = frame.width - mainSplitPane.border = BorderFactory.createEmptyBorder() - mainSplitPane.dividerSize = 1 - mainSplitPane.resizeWeight = 0.5 - mainSplitPane.rightComponent = null - - val toolbar = JToolBar() - toolbar.orientation = SwingConstants.VERTICAL - - val inspectorIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("toolbox.png"), 16, 16) - val inspectorButton = JToggleButton() - inspectorButton.toolTipText = "Inspector" - - val inspectorAction = object: AbstractAction("Inspector", inspectorIcon) { - override fun actionPerformed(e: ActionEvent) { - container.toggleSidebarComponent(inspector, toolbar, inspectorButton, e) + val toolbar = JToolBar() + toolbar.orientation = SwingConstants.VERTICAL + + val inspectorIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("toolbox.png"), 16, 16) + val inspectorButton = JToggleButton() + inspectorButton.toolTipText = "Inspector" + + val inspectorAction = object : AbstractAction("Inspector", inspectorIcon) { + override fun actionPerformed(e: ActionEvent) { + container.toggleSidebarComponent(inspector, toolbar, inspectorButton, e) + } } - } - defaultSidebarAction = { container.toggleSidebarComponent(inspector, toolbar, inspectorButton, null) } + defaultSidebarAction = { container.toggleSidebarComponent(inspector, toolbar, inspectorButton, null) } - inspectorButton.action = inspectorAction - inspectorButton.icon = inspectorIcon - inspectorButton.hideActionText = true + inspectorButton.action = inspectorAction + inspectorButton.icon = inspectorIcon + inspectorButton.hideActionText = true - val replIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("terminal.png"), 16, 16) - val replButton = JToggleButton() - replButton.toolTipText = "Script Interpreter" + val replIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("terminal.png"), 16, 16) + val replButton = JToggleButton() + replButton.toolTipText = "Script Interpreter" - val replAction = object: AbstractAction("REPL", replIcon) { - override fun actionPerformed(e: ActionEvent) { - container.toggleSidebarComponent(interpreterPane.component, toolbar, replButton, e) + val replAction = object : AbstractAction("REPL", replIcon) { + override fun actionPerformed(e: ActionEvent) { + container.toggleSidebarComponent(interpreterPane.component, toolbar, replButton, e) + } } - } - replButton.action = replAction - replButton.icon = replIcon - replButton.hideActionText = true - - toolbar.add(inspectorButton) - toolbar.add(replButton) - - //frame.add(mainSplitPane, BorderLayout.CENTER); - frame.add(mainSplitPane, BorderLayout.CENTER) - frame.add(toolbar, BorderLayout.EAST) - frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE - frame.addWindowListener(object : WindowAdapter() { - override fun windowClosing(e: WindowEvent) { - logger.debug("Closing SciView window.") - close() - sciview.scijavaContext?.service(SciViewService::class.java)?.close(sciview) - sciview.isClosed = true - } - }) - - frame.isVisible = true - glassPane.repaint() - - sciview.sceneryPanel[0] = sceneryJPanel - val renderer = Renderer.createRenderer( - sciview.hub, - sciview.applicationName, - sciview.currentScene, - sciview.windowWidth, - sciview.windowHeight, - sciview.sceneryPanel[0] - ) - - sciview.setRenderer(renderer) - sciview.hub.add(SceneryElement.Renderer, renderer) - sciview.reset() - - SwingUtilities.invokeLater { - try { - while (!sciview.getSceneryRenderer()!!.firstImageReady) { - logger.debug("Waiting for renderer initialisation") - Thread.sleep(300) + replButton.action = replAction + replButton.icon = replIcon + replButton.hideActionText = true + + toolbar.add(inspectorButton) + toolbar.add(replButton) + + //frame.add(mainSplitPane, BorderLayout.CENTER); + frame.add(mainSplitPane, BorderLayout.CENTER) + frame.add(toolbar, BorderLayout.EAST) + frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE + frame.addWindowListener(object : WindowAdapter() { + override fun windowClosing(e: WindowEvent) { + logger.debug("Closing SciView window.") + close() + sciview.scijavaContext?.service(SciViewService::class.java)?.close(sciview) + sciview.isClosed = true } - Thread.sleep(200) - } catch (e: InterruptedException) { - logger.error("Renderer construction interrupted.") - } - nodePropertyEditor.rebuildTree() - logger.info("Done initializing SciView") + }) + + frame.isVisible = true + glassPane.repaint() + + sciview.sceneryPanel[0] = sceneryJPanel + val renderer = Renderer.createRenderer( + sciview.hub, + sciview.applicationName, + sciview.currentScene, + sciview.windowWidth, + sciview.windowHeight, + sciview.sceneryPanel[0] + ) + + sciview.setRenderer(renderer) + sciview.hub.add(SceneryElement.Renderer, renderer) + sciview.reset() + + SwingUtilities.invokeLater { + try { + while (!sciview.getSceneryRenderer()!!.firstImageReady) { + logger.debug("Waiting for renderer initialisation") + Thread.sleep(300) + } + Thread.sleep(200) + } catch (e: InterruptedException) { + logger.error("Renderer construction interrupted.") + } + nodePropertyEditor.rebuildTree() + logger.info("Done initializing SciView") - // subscribe to Node{Added, Removed, Changed} events, happens automatically + // subscribe to Node{Added, Removed, Changed} events, happens automatically // eventService!!.subscribe(this) - sceneryJPanel.isVisible = true + sceneryJPanel.isVisible = true - // install hook to keep inspector updated on external changes (scripting, etc) - sciview.currentScene.onNodePropertiesChanged["updateInspector"] = { node: Node -> - if (node === nodePropertyEditor.currentNode) { - nodePropertyEditor.updateProperties(node) + // install hook to keep inspector updated on external changes (scripting, etc) + sciview.currentScene.onNodePropertiesChanged["updateInspector"] = { node: Node -> + if (node === nodePropertyEditor.currentNode) { + nodePropertyEditor.updateProperties(node) + } } - } - // Enable push rendering by default - renderer.pushMode = true - sciview.camera!!.setPosition(1.65, 1) - glassPane.isVisible = false + // Enable push rendering by default + renderer.pushMode = true + sciview.camera!!.setPosition(1.65, 1) + glassPane.isVisible = false + + sceneryJPanel.minimumSize = Dimension(256, 256) + } + } - sceneryJPanel.minimumSize = Dimension(256, 256) + if(SwingUtilities.isEventDispatchThread()) { + initializer.run() + } else { + SwingUtilities.invokeAndWait(initializer) } } From 933627221592c6de3484d362f7961a82d16761c5 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 16:18:21 +0200 Subject: [PATCH 05/29] Gradle: Bump to latest staging repo for scenery --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 996f56db..e6b98708 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1221") + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } From bc95ffa49e8004ddcb9d5cd8264f8b55e2c4d841 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 16:20:07 +0200 Subject: [PATCH 06/29] SwingNodePropertyEditor: Add TransferFunctionEditor for volumes --- src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt index 83f517e4..4e4a995a 100644 --- a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt +++ b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt @@ -32,6 +32,8 @@ import com.intellij.ui.components.JBPanel import graphics.scenery.Camera import graphics.scenery.Node import graphics.scenery.Scene +import graphics.scenery.volumes.TransferFunctionEditor +import graphics.scenery.volumes.Volume import net.miginfocom.swing.MigLayout import org.joml.Quaternionf import org.joml.Vector3f @@ -340,6 +342,13 @@ class SwingNodePropertyEditor(private val sciView: SciView) : UIComponent Date: Fri, 14 Jul 2023 08:06:05 -0400 Subject: [PATCH 07/29] Switch to main repo from staging --- build.gradle.kts | 1 - .../commands/demo/advanced/OpenOrganelle.kt | 256 ------------------ 2 files changed, 257 deletions(-) delete mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/build.gradle.kts b/build.gradle.kts index 8483ba87..e1c4f8ae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,6 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt deleted file mode 100644 index da14037a..00000000 --- a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt +++ /dev/null @@ -1,256 +0,0 @@ -package sc.iview.commands.demo.advanced - -import graphics.scenery.Origin -import graphics.scenery.utils.extensions.xyz -import graphics.scenery.volumes.Colormap -import graphics.scenery.volumes.TransferFunction -import net.imagej.lut.LUTService -import net.imagej.mesh.Mesh -import net.imagej.mesh.Meshes -import net.imagej.ops.OpService -import net.imglib2.RandomAccessibleInterval -import net.imglib2.cache.img.CachedCellImg -import net.imglib2.roi.labeling.ImgLabeling -import net.imglib2.roi.labeling.LabelRegions -import net.imglib2.type.NativeType -import net.imglib2.type.numeric.ARGBType -import net.imglib2.type.numeric.RealType -import net.imglib2.view.Views -import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer -import org.janelia.saalfeldlab.n5.N5Reader -import org.janelia.saalfeldlab.n5.N5TreeNode -import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets -import org.janelia.saalfeldlab.n5.ij.N5Factory -import org.janelia.saalfeldlab.n5.ij.N5Importer -import org.janelia.saalfeldlab.n5.imglib2.N5Utils -import org.janelia.saalfeldlab.n5.metadata.* -import org.janelia.saalfeldlab.n5.ui.DataSelection -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 sc.iview.commands.demo.basic.VolumeRenderDemo -import sc.iview.process.MeshConverter -import java.io.File -import java.io.IOException -import java.util.* -import java.util.concurrent.Executors - - -@Plugin(type = Command::class, - label = "OpenOrganelle demo", - menuRoot = "SciView", - menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), - Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), - Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) -class OpenOrganelle : Command { - @Parameter - private lateinit var ui: UIService - - @Parameter - private lateinit var log: LogService - - @Parameter - private lateinit var ops: OpService - - @Parameter - private lateinit var sciview: SciView - - @Parameter - private lateinit var lut: LUTService - - /* - * TODO - * - * https://openorganelle.janelia.org/datasets/jrc_mus-kidney - * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 - * - */ - - internal class DefaultLabelIterator : MutableIterator { - private var i = 0L - override fun hasNext(): Boolean { - return i < Long.MAX_VALUE - } - - override fun next(): Long { - return i++ - } - - override fun remove() { - throw UnsupportedOperationException() - } - } - - /** - * 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("OpenOrganelle", "Loading dataset") - - val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") - - // Read the EM volume - task.status = "Reading image volume" - //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") - log.info("Start Reading") - val nai = readMultiscaleN5() - - log.info("Done Reading") - - if (nai == null) { - log.error("Could not read data") - return - } -// val raiVolume = nai.third -// val cursor = Views.iterable(raiVolume).localizingCursor() -// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { -// cursor.fwd() -// cursor.get().set(0) -// } -// - val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) -// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) - -// sciview.addVolume(nai) { -// origin = Origin.FrontBottomLeft -// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) -// 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(20.0, 220.0) -// colormap = Colormap.fromColorTable(colormapVolume) -// } - - // Read the labels volume - task.status = "Reading labels volume" - val labels = readMultiscaleN5() - - task.status = "Creating labeling" - task.completion = 10.0f -// val rai = nai.second -// log.info("Got ${nai.first.size} labels") - - // let's extract some neurons here - log.info("Creating labeling ...") - - //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() -// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) -// log.info("Creating regions...") -// val regions = LabelRegions(labeling) -// log.info("Created ${regions.count()} regions") -// -// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } -// -// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") -// -// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> -// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") -// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" -// -// // ui.show(region) -// // Generate the mesh with imagej-ops -// val m: Mesh = Meshes.marchingCubes(region); -// -// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") -// // Convert the mesh into a scenery mesh for visualization -// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) -// sciview.addNode(mesh) { -// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) -// ifMaterial { -// diffuse = -// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() -// .xyz() -// roughness = 0.0f -// } -// name = "Neuron $i" -// } -// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f -// task.completion = completion -// } -// -// task.completion = 100.0f - } - - - - fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", - multiscaleBaseDataset: String = "/labels/empanada-mito_seg", - scale: Double = 1.0): CachedCellImg, *>? { - // set up the n5 reader - - log.info("Opening reader") - var n5: N5Reader = N5Factory().openReader(n5root) - // parse the metadata so bdv knows how to display the scales - val importers = Arrays.asList>(*N5Importer.PARSERS) - val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) - log.info("Dataset discoverer") - val parsers = N5DatasetDiscoverer( - n5, - Executors.newSingleThreadExecutor(), - importers, - groupParsers - ) - - log.info("Dataset discoverer done") - - // get the particular metadata we care above - var root = parsers.discoverAndParseRecursive("") - val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata - - var datasetToOpen = multiscaleMetadata.path - - log.info("Opening image") - - var img = N5Utils.openVolatile(n5, datasetToOpen) - - log.info("Image opened") - - // run n5 viewer - //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); - - - return img - } - - - private fun Int.toRGBColor(): Vector4f { - val a = ARGBType.alpha(this) / 255.0f - val r = ARGBType.red(this) / 255.0f - val g = ARGBType.green(this) / 255.0f - val b = ARGBType.blue(this) / 255.0f - - return Vector4f(r, g, b, a) - } - - - 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(OpenOrganelle::class.java, true, argmap) - } - } -} \ No newline at end of file From 6a61f6a9ee88016453c4ce091e2f988372738c83 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:10:43 -0400 Subject: [PATCH 08/29] Revert "Switch to main repo from staging" This reverts commit 977e9aa1a9f7de89e131060a1b5cbe2cb67b3e38. --- build.gradle.kts | 1 + .../commands/demo/advanced/OpenOrganelle.kt | 256 ++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/build.gradle.kts b/build.gradle.kts index e1c4f8ae..8483ba87 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,7 @@ repositories { mavenLocal() } mavenCentral() + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt new file mode 100644 index 00000000..da14037a --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt @@ -0,0 +1,256 @@ +package sc.iview.commands.demo.advanced + +import graphics.scenery.Origin +import graphics.scenery.utils.extensions.xyz +import graphics.scenery.volumes.Colormap +import graphics.scenery.volumes.TransferFunction +import net.imagej.lut.LUTService +import net.imagej.mesh.Mesh +import net.imagej.mesh.Meshes +import net.imagej.ops.OpService +import net.imglib2.RandomAccessibleInterval +import net.imglib2.cache.img.CachedCellImg +import net.imglib2.roi.labeling.ImgLabeling +import net.imglib2.roi.labeling.LabelRegions +import net.imglib2.type.NativeType +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.RealType +import net.imglib2.view.Views +import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer +import org.janelia.saalfeldlab.n5.N5Reader +import org.janelia.saalfeldlab.n5.N5TreeNode +import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets +import org.janelia.saalfeldlab.n5.ij.N5Factory +import org.janelia.saalfeldlab.n5.ij.N5Importer +import org.janelia.saalfeldlab.n5.imglib2.N5Utils +import org.janelia.saalfeldlab.n5.metadata.* +import org.janelia.saalfeldlab.n5.ui.DataSelection +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 sc.iview.commands.demo.basic.VolumeRenderDemo +import sc.iview.process.MeshConverter +import java.io.File +import java.io.IOException +import java.util.* +import java.util.concurrent.Executors + + +@Plugin(type = Command::class, + label = "OpenOrganelle demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) +class OpenOrganelle : Command { + @Parameter + private lateinit var ui: UIService + + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var ops: OpService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + /* + * TODO + * + * https://openorganelle.janelia.org/datasets/jrc_mus-kidney + * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 + * + */ + + internal class DefaultLabelIterator : MutableIterator { + private var i = 0L + override fun hasNext(): Boolean { + return i < Long.MAX_VALUE + } + + override fun next(): Long { + return i++ + } + + override fun remove() { + throw UnsupportedOperationException() + } + } + + /** + * 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("OpenOrganelle", "Loading dataset") + + val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") + + // Read the EM volume + task.status = "Reading image volume" + //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") + log.info("Start Reading") + val nai = readMultiscaleN5() + + log.info("Done Reading") + + if (nai == null) { + log.error("Could not read data") + return + } +// val raiVolume = nai.third +// val cursor = Views.iterable(raiVolume).localizingCursor() +// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { +// cursor.fwd() +// cursor.get().set(0) +// } +// + val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) +// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) + +// sciview.addVolume(nai) { +// origin = Origin.FrontBottomLeft +// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) +// 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(20.0, 220.0) +// colormap = Colormap.fromColorTable(colormapVolume) +// } + + // Read the labels volume + task.status = "Reading labels volume" + val labels = readMultiscaleN5() + + task.status = "Creating labeling" + task.completion = 10.0f +// val rai = nai.second +// log.info("Got ${nai.first.size} labels") + + // let's extract some neurons here + log.info("Creating labeling ...") + + //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() +// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) +// log.info("Creating regions...") +// val regions = LabelRegions(labeling) +// log.info("Created ${regions.count()} regions") +// +// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } +// +// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") +// +// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> +// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") +// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" +// +// // ui.show(region) +// // Generate the mesh with imagej-ops +// val m: Mesh = Meshes.marchingCubes(region); +// +// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") +// // Convert the mesh into a scenery mesh for visualization +// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) +// sciview.addNode(mesh) { +// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) +// ifMaterial { +// diffuse = +// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() +// .xyz() +// roughness = 0.0f +// } +// name = "Neuron $i" +// } +// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f +// task.completion = completion +// } +// +// task.completion = 100.0f + } + + + + fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", + multiscaleBaseDataset: String = "/labels/empanada-mito_seg", + scale: Double = 1.0): CachedCellImg, *>? { + // set up the n5 reader + + log.info("Opening reader") + var n5: N5Reader = N5Factory().openReader(n5root) + // parse the metadata so bdv knows how to display the scales + val importers = Arrays.asList>(*N5Importer.PARSERS) + val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) + log.info("Dataset discoverer") + val parsers = N5DatasetDiscoverer( + n5, + Executors.newSingleThreadExecutor(), + importers, + groupParsers + ) + + log.info("Dataset discoverer done") + + // get the particular metadata we care above + var root = parsers.discoverAndParseRecursive("") + val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata + + var datasetToOpen = multiscaleMetadata.path + + log.info("Opening image") + + var img = N5Utils.openVolatile(n5, datasetToOpen) + + log.info("Image opened") + + // run n5 viewer + //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); + + + return img + } + + + private fun Int.toRGBColor(): Vector4f { + val a = ARGBType.alpha(this) / 255.0f + val r = ARGBType.red(this) / 255.0f + val g = ARGBType.green(this) / 255.0f + val b = ARGBType.blue(this) / 255.0f + + return Vector4f(r, g, b, a) + } + + + 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(OpenOrganelle::class.java, true, argmap) + } + } +} \ No newline at end of file From 00172da5037f94b5c38bd5f3a65e048e56f03b21 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:12:44 -0400 Subject: [PATCH 09/29] Remove OpenOrganelle demo that was accidentally added too early --- .../commands/demo/advanced/OpenOrganelle.kt | 256 ------------------ 1 file changed, 256 deletions(-) delete mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt deleted file mode 100644 index da14037a..00000000 --- a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt +++ /dev/null @@ -1,256 +0,0 @@ -package sc.iview.commands.demo.advanced - -import graphics.scenery.Origin -import graphics.scenery.utils.extensions.xyz -import graphics.scenery.volumes.Colormap -import graphics.scenery.volumes.TransferFunction -import net.imagej.lut.LUTService -import net.imagej.mesh.Mesh -import net.imagej.mesh.Meshes -import net.imagej.ops.OpService -import net.imglib2.RandomAccessibleInterval -import net.imglib2.cache.img.CachedCellImg -import net.imglib2.roi.labeling.ImgLabeling -import net.imglib2.roi.labeling.LabelRegions -import net.imglib2.type.NativeType -import net.imglib2.type.numeric.ARGBType -import net.imglib2.type.numeric.RealType -import net.imglib2.view.Views -import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer -import org.janelia.saalfeldlab.n5.N5Reader -import org.janelia.saalfeldlab.n5.N5TreeNode -import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets -import org.janelia.saalfeldlab.n5.ij.N5Factory -import org.janelia.saalfeldlab.n5.ij.N5Importer -import org.janelia.saalfeldlab.n5.imglib2.N5Utils -import org.janelia.saalfeldlab.n5.metadata.* -import org.janelia.saalfeldlab.n5.ui.DataSelection -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 sc.iview.commands.demo.basic.VolumeRenderDemo -import sc.iview.process.MeshConverter -import java.io.File -import java.io.IOException -import java.util.* -import java.util.concurrent.Executors - - -@Plugin(type = Command::class, - label = "OpenOrganelle demo", - menuRoot = "SciView", - menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), - Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), - Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) -class OpenOrganelle : Command { - @Parameter - private lateinit var ui: UIService - - @Parameter - private lateinit var log: LogService - - @Parameter - private lateinit var ops: OpService - - @Parameter - private lateinit var sciview: SciView - - @Parameter - private lateinit var lut: LUTService - - /* - * TODO - * - * https://openorganelle.janelia.org/datasets/jrc_mus-kidney - * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 - * - */ - - internal class DefaultLabelIterator : MutableIterator { - private var i = 0L - override fun hasNext(): Boolean { - return i < Long.MAX_VALUE - } - - override fun next(): Long { - return i++ - } - - override fun remove() { - throw UnsupportedOperationException() - } - } - - /** - * 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("OpenOrganelle", "Loading dataset") - - val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") - - // Read the EM volume - task.status = "Reading image volume" - //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") - log.info("Start Reading") - val nai = readMultiscaleN5() - - log.info("Done Reading") - - if (nai == null) { - log.error("Could not read data") - return - } -// val raiVolume = nai.third -// val cursor = Views.iterable(raiVolume).localizingCursor() -// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { -// cursor.fwd() -// cursor.get().set(0) -// } -// - val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) -// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) - -// sciview.addVolume(nai) { -// origin = Origin.FrontBottomLeft -// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) -// 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(20.0, 220.0) -// colormap = Colormap.fromColorTable(colormapVolume) -// } - - // Read the labels volume - task.status = "Reading labels volume" - val labels = readMultiscaleN5() - - task.status = "Creating labeling" - task.completion = 10.0f -// val rai = nai.second -// log.info("Got ${nai.first.size} labels") - - // let's extract some neurons here - log.info("Creating labeling ...") - - //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() -// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) -// log.info("Creating regions...") -// val regions = LabelRegions(labeling) -// log.info("Created ${regions.count()} regions") -// -// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } -// -// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") -// -// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> -// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") -// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" -// -// // ui.show(region) -// // Generate the mesh with imagej-ops -// val m: Mesh = Meshes.marchingCubes(region); -// -// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") -// // Convert the mesh into a scenery mesh for visualization -// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) -// sciview.addNode(mesh) { -// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) -// ifMaterial { -// diffuse = -// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() -// .xyz() -// roughness = 0.0f -// } -// name = "Neuron $i" -// } -// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f -// task.completion = completion -// } -// -// task.completion = 100.0f - } - - - - fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", - multiscaleBaseDataset: String = "/labels/empanada-mito_seg", - scale: Double = 1.0): CachedCellImg, *>? { - // set up the n5 reader - - log.info("Opening reader") - var n5: N5Reader = N5Factory().openReader(n5root) - // parse the metadata so bdv knows how to display the scales - val importers = Arrays.asList>(*N5Importer.PARSERS) - val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) - log.info("Dataset discoverer") - val parsers = N5DatasetDiscoverer( - n5, - Executors.newSingleThreadExecutor(), - importers, - groupParsers - ) - - log.info("Dataset discoverer done") - - // get the particular metadata we care above - var root = parsers.discoverAndParseRecursive("") - val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata - - var datasetToOpen = multiscaleMetadata.path - - log.info("Opening image") - - var img = N5Utils.openVolatile(n5, datasetToOpen) - - log.info("Image opened") - - // run n5 viewer - //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); - - - return img - } - - - private fun Int.toRGBColor(): Vector4f { - val a = ARGBType.alpha(this) / 255.0f - val r = ARGBType.red(this) / 255.0f - val g = ARGBType.green(this) / 255.0f - val b = ARGBType.blue(this) / 255.0f - - return Vector4f(r, g, b, a) - } - - - 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(OpenOrganelle::class.java, true, argmap) - } - } -} \ No newline at end of file From 1404e78b4efd5a533ab2790b9d008f003eec461c Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:16:18 -0400 Subject: [PATCH 10/29] Remove OpenOrganelle menu weight --- src/main/kotlin/sc/iview/commands/MenuWeights.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/sc/iview/commands/MenuWeights.kt b/src/main/kotlin/sc/iview/commands/MenuWeights.kt index c3d9eaef..5e224bdf 100644 --- a/src/main/kotlin/sc/iview/commands/MenuWeights.kt +++ b/src/main/kotlin/sc/iview/commands/MenuWeights.kt @@ -115,7 +115,6 @@ object MenuWeights { const val DEMO_ADVANCED_CREMI = 1.0 const val DEMO_ADVANCED_BDVSLICING = 2.0 const val DEMO_ADVANCED_MESHTEXTURE = 3.0 - const val DEMO_ADVANCED_OPENORGANELLE = 4.0 // Help const val HELP_HELP = 0.0 const val HELP_ABOUT = 200.0 From 9b1d9a4ed2a80a3884f30bf758ebacad8a4907dd Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:17:02 -0400 Subject: [PATCH 11/29] Switch to main repo from staging --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8483ba87..e1c4f8ae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,6 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } From 9ece14347221cfefd0459257b1276c0b5f19cda6 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 15:01:19 +0200 Subject: [PATCH 12/29] Gradle: Bump scenery to 0.9.0, pom-scijava to 35.1.1, fix snakeyaml to 1.33 --- build.gradle.kts | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b0ab7430..996f56db 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ import java.net.URL import sciview.* plugins { - val ktVersion = "1.8.20" + val ktVersion = "1.8.22" val dokkaVersion = "1.8.20" java @@ -25,43 +25,48 @@ java { } repositories { + if(project.properties["useMavenLocal"] == "true") { + logger.warn("Using local Maven repository as source") + mavenLocal() + } mavenCentral() + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1221") maven("https://maven.scijava.org/content/groups/public") } dependencies { - val ktVersion = "1.8.20" - implementation(platform("org.scijava:pom-scijava:31.1.0")) + val ktVersion = "1.8.22" + implementation(platform("org.scijava:pom-scijava:35.1.1")) // Graphics dependencies - annotationProcessor("org.scijava:scijava-common:2.90.0") - kapt("org.scijava:scijava-common:2.90.0") { // MANUAL version increment + // Attention! Manual version increment necessary here! + val scijavaCommonVersion = "2.94.1" + annotationProcessor("org.scijava:scijava-common:$scijavaCommonVersion") + kapt("org.scijava:scijava-common:$scijavaCommonVersion") { exclude("org.lwjgl") } - val sceneryVersion = "0.8.0" + val sceneryVersion = "0.9.0" api("graphics.scenery:scenery:$sceneryVersion") { version { strictly(sceneryVersion) } exclude("org.biojava.thirdparty", "forester") exclude("null", "unspecified") } - implementation("com.fasterxml.jackson.core:jackson-databind:2.13.4.2") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.4") - implementation("org.msgpack:jackson-dataformat-msgpack:0.9.3") implementation("net.java.dev.jna:jna-platform:5.11.0") - implementation("net.clearvolume:cleargl") implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-imglib2") implementation("org.apache.logging.log4j:log4j-api:2.20.0") implementation("org.apache.logging.log4j:log4j-1.2-api:2.20.0") - implementation("com.formdev:flatlaf:2.6") + implementation("com.formdev:flatlaf") // SciJava dependencies + implementation("org.yaml:snakeyaml") { + version { strictly("1.33") } + } implementation("org.scijava:scijava-common") implementation("org.scijava:ui-behaviour") implementation("org.scijava:script-editor") @@ -435,5 +440,7 @@ artifacts { archives(dokkaHtmlJar) } + + java.withSourcesJar() From 210d9a059946e84b3afff853de3bcdc6a38f0232 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 15:01:57 +0200 Subject: [PATCH 13/29] Adjust for changed APIs in scenery 0.9.0 --- .../commands/demo/animation/SceneRiggingDemo.java | 2 +- .../commands/edit/add/AddOrientationCompass.java | 2 +- src/main/java/sc/iview/io/N5IO.java | 2 +- src/main/kotlin/sc/iview/SciView.kt | 8 +++----- src/test/java/sc/iview/SciViewTest.java | 11 +++++------ 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java b/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java index 853a17e1..bfc506f9 100644 --- a/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java +++ b/src/main/java/sc/iview/commands/demo/animation/SceneRiggingDemo.java @@ -113,7 +113,7 @@ public void run() { sciView.centerOnNode( sciView.getActiveNode() ); for( PointLight light : sciView.getLights() ) { - Icosphere s = new Icosphere(1f, 1); + Icosphere s = new Icosphere(1f, 1, false); s.getMaterial().setDiffuse(light.getEmissionColor()); s.getMaterial().setAmbient(light.getEmissionColor()); s.getMaterial().setSpecular(light.getEmissionColor()); diff --git a/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java b/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java index ad8ddb81..74d524d0 100644 --- a/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java +++ b/src/main/java/sc/iview/commands/edit/add/AddOrientationCompass.java @@ -86,7 +86,7 @@ private Node makeAxis( float axisLength, float angleX, float angleY, float angle return null; }); - Icosphere axisCap = new Icosphere(AXESBARRADIUS, 2); + Icosphere axisCap = new Icosphere(AXESBARRADIUS, 2, false); axisCap.ifSpatial(spatial -> { spatial.setPosition(new Vector3f(0, axisLength, 0)); return null; diff --git a/src/main/java/sc/iview/io/N5IO.java b/src/main/java/sc/iview/io/N5IO.java index e7f44569..1c8407c2 100644 --- a/src/main/java/sc/iview/io/N5IO.java +++ b/src/main/java/sc/iview/io/N5IO.java @@ -29,6 +29,7 @@ package sc.iview.io; import bdv.util.AxisOrder; +import bvv.core.VolumeViewerOptions; import graphics.scenery.Group; import graphics.scenery.Node; import graphics.scenery.primitives.PointCloud; @@ -46,7 +47,6 @@ import sc.iview.SciView; import sc.iview.SciViewService; import sc.iview.process.MeshConverter; -import tpietzsch.example2.VolumeViewerOptions; import java.io.File; import java.io.IOException; diff --git a/src/main/kotlin/sc/iview/SciView.kt b/src/main/kotlin/sc/iview/SciView.kt index 88eee9b4..f7b4b376 100644 --- a/src/main/kotlin/sc/iview/SciView.kt +++ b/src/main/kotlin/sc/iview/SciView.kt @@ -37,11 +37,11 @@ import bdv.util.RandomAccessibleIntervalSource4D import bdv.util.volatiles.VolatileView import bdv.viewer.Source import bdv.viewer.SourceAndConverter +import bvv.core.VolumeViewerOptions import dev.dirs.ProjectDirectories import graphics.scenery.* import graphics.scenery.Scene.RaycastResult import graphics.scenery.backends.Renderer -import graphics.scenery.backends.opengl.OpenGLRenderer import graphics.scenery.backends.vulkan.VulkanRenderer import graphics.scenery.controls.InputHandler import graphics.scenery.controls.OpenVRHMD @@ -110,7 +110,6 @@ import sc.iview.ui.CustomPropertyUI import sc.iview.ui.MainWindow import sc.iview.ui.SwingMainWindow import sc.iview.ui.TaskManager -import tpietzsch.example2.VolumeViewerOptions import java.awt.event.WindowListener import java.io.IOException import java.net.URL @@ -388,10 +387,9 @@ class SciView : SceneryBase, CalibratedRealInterval { versionString = versionString.substring(0, 5) val launcherVersion = Version(versionString) val nonWorkingVersion = Version("4.0.5") - if (launcherVersion.compareTo(nonWorkingVersion) <= 0 + if (launcherVersion <= nonWorkingVersion && !java.lang.Boolean.parseBoolean(System.getProperty("sciview.DisableLauncherVersionCheck", "false"))) { - logger.info("imagej-launcher version smaller or equal to non-working version ($versionString vs. 4.0.5), disabling Vulkan as rendering backend. Disable check by setting 'scenery.DisableLauncherVersionCheck' system property to 'true'.") - System.setProperty("scenery.Renderer", "OpenGLRenderer") + throw IllegalStateException("imagej-launcher version is outdated, please update your Fiji installation.") } else { logger.info("imagej-launcher version bigger that non-working version ($versionString vs. 4.0.5), all good.") } diff --git a/src/test/java/sc/iview/SciViewTest.java b/src/test/java/sc/iview/SciViewTest.java index 96f0d7b6..6166ba4e 100644 --- a/src/test/java/sc/iview/SciViewTest.java +++ b/src/test/java/sc/iview/SciViewTest.java @@ -28,9 +28,10 @@ */ package sc.iview; -import cleargl.GLVector; -import graphics.scenery.*; -import graphics.scenery.attribute.material.Material; +import graphics.scenery.Group; +import graphics.scenery.Node; +import graphics.scenery.SceneryBase; +import graphics.scenery.Sphere; import io.scif.SCIFIOService; import net.imagej.ImageJService; import org.joml.Vector3f; @@ -38,8 +39,6 @@ import org.scijava.Context; import org.scijava.service.SciJavaService; import org.scijava.thread.ThreadService; -import sc.iview.SciView; -import sc.iview.SciViewService; public class SciViewTest { @@ -77,7 +76,7 @@ public void nestedNodeDeletionTest() throws Exception { Group group = new Group(); - final Sphere sphere = new Sphere( 1, 20 ); + final Sphere sphere = new Sphere( 1, 20, false ); sphere.ifMaterial( material -> { material.setAmbient( new Vector3f( 1.0f, 0.0f, 0.0f ) ); material.setDiffuse( new Vector3f( 1.0f, 0.0f, 0.0f ) ); From 5f05973b0bdcd6a32d974aa1aa7d2565cfc4a0e1 Mon Sep 17 00:00:00 2001 From: Samuel Pantze <83579186+smlpt@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:29:53 +0200 Subject: [PATCH 14/29] SwingSwapchain/REPLPane: Do UI initialisation on EDT, initialise REPL asynchronously --- src/main/java/sc/iview/ui/REPLPane.java | 4 +- .../kotlin/sc/iview/ui/SwingMainWindow.kt | 396 +++++++++--------- 2 files changed, 206 insertions(+), 194 deletions(-) diff --git a/src/main/java/sc/iview/ui/REPLPane.java b/src/main/java/sc/iview/ui/REPLPane.java index 76376259..ae617426 100644 --- a/src/main/java/sc/iview/ui/REPLPane.java +++ b/src/main/java/sc/iview/ui/REPLPane.java @@ -75,7 +75,7 @@ public REPLPane(final Context context) { final JScrollPane outputScroll = new JScrollPane(output); outputScroll.setPreferredSize(new Dimension(440, 400)); - repl = new ScriptREPL(context, output.getOutputStream()); + repl = new ScriptREPL(context, "Python (Jython)", output.getOutputStream()); repl.initialize(); final Writer writer = output.getOutputWriter(); @@ -89,7 +89,7 @@ public REPLPane(final Context context) { //prompt = new REPLEditor(repl, vars, output); prompt = new REPLEditor(repl, null, output); context.inject(prompt); - prompt.setREPLLanguage("Python"); + final JScrollPane promptScroll = new JScrollPane(prompt); final JPanel bottomPane = new JPanel(); diff --git a/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt b/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt index 1404b555..2faf5037 100644 --- a/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt +++ b/src/main/kotlin/sc/iview/ui/SwingMainWindow.kt @@ -46,6 +46,7 @@ import java.awt.event.* import java.util.* import javax.script.ScriptException import javax.swing.* +import kotlin.concurrent.thread import kotlin.math.roundToInt /** @@ -58,228 +59,239 @@ class SwingMainWindow(val sciview: SciView) : MainWindow { private val logger by lazyLogger() private var previousSidebarPosition = 0 - var sceneryJPanel: SceneryJPanel + lateinit var sceneryJPanel: SceneryJPanel private set - var mainSplitPane: JSplitPane + lateinit var mainSplitPane: JSplitPane protected set - var inspector: JSplitPane + lateinit var inspector: JSplitPane protected set - var interpreterPane: REPLPane + lateinit var interpreterPane: REPLPane protected set - var nodePropertyEditor: SwingNodePropertyEditor + lateinit var nodePropertyEditor: SwingNodePropertyEditor protected set - var frame: JFrame + lateinit var frame: JFrame protected set var sidebarOpen = false protected set - private var splashLabel: SplashLabel + private lateinit var splashLabel: SplashLabel private var defaultSidebarAction: (() -> Any)? = null init { - FlatLightLaf.setup() - try { - UIManager.setLookAndFeel(FlatLightLaf()) - } catch (ex: Exception) { - System.err.println("Failed to initialize Flat Light LaF, falling back to Swing default.") - } + val initializer = Runnable { + FlatLightLaf.setup() + try { + UIManager.setLookAndFeel(FlatLightLaf()) + } catch (ex: Exception) { + System.err.println("Failed to initialize Flat Light LaF, falling back to Swing default.") + } - var x: Int - var y: Int - try { - val screenSize = Toolkit.getDefaultToolkit().screenSize - x = screenSize.width / 2 - sciview.windowWidth / 2 - y = screenSize.height / 2 - sciview.windowHeight / 2 - } catch (e: HeadlessException) { - x = 10 - y = 10 - } + var x: Int + var y: Int + try { + val screenSize = Toolkit.getDefaultToolkit().screenSize + x = screenSize.width / 2 - sciview.windowWidth / 2 + y = screenSize.height / 2 - sciview.windowHeight / 2 + } catch (e: HeadlessException) { + x = 10 + y = 10 + } - frame = JFrame("sciview") - frame.layout = BorderLayout(0, 0) - frame.setSize(sciview.windowWidth, sciview.windowHeight) - frame.setLocation(x, y) - - splashLabel = SplashLabel() - val glassPane = frame.glassPane as JPanel - glassPane.isVisible = true - glassPane.layout = BorderLayout() - glassPane.isOpaque = false - glassPane.add(splashLabel, BorderLayout.CENTER) - glassPane.requestFocusInWindow() - glassPane.revalidate() - - frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE - nodePropertyEditor = SwingNodePropertyEditor(sciview) - - sceneryJPanel = SceneryJPanel() - JPopupMenu.setDefaultLightWeightPopupEnabled(false) - val swingMenuBar = JMenuBar() - val menus = sciview.scijavaContext?.getService(MenuService::class.java) ?: throw IllegalStateException("MenuService not available") - SwingJMenuBarCreator().createMenus(menus.getMenu("SciView"), swingMenuBar) - - val bar = ProgressPie() - bar.value = 0.0 - bar.minimumSize = Dimension(30, 30) - bar.maximumSize = Dimension(30, 30) - bar.preferredSize = Dimension(30, 30) - val progressLabel = JLabel("") - progressLabel.horizontalAlignment = SwingConstants.RIGHT - swingMenuBar.add(Box.createHorizontalGlue()) - swingMenuBar.add(progressLabel) - swingMenuBar.add(bar) - frame.jMenuBar = swingMenuBar - - sciview.taskManager.update = { current -> - if(current != null) { - progressLabel.text = "${current.source}: ${current.status} " - bar.value = current.completion.toDouble() - } else { - progressLabel.text = "" - bar.value = 0.0 + frame = JFrame("sciview") + frame.layout = BorderLayout(0, 0) + frame.setSize(sciview.windowWidth, sciview.windowHeight) + frame.setLocation(x, y) + + splashLabel = SplashLabel() + val glassPane = frame.glassPane as JPanel + glassPane.isVisible = true + glassPane.layout = BorderLayout() + glassPane.isOpaque = false + glassPane.add(splashLabel, BorderLayout.CENTER) + glassPane.requestFocusInWindow() + glassPane.revalidate() + + frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE + nodePropertyEditor = SwingNodePropertyEditor(sciview) + + sceneryJPanel = SceneryJPanel() + JPopupMenu.setDefaultLightWeightPopupEnabled(false) + val swingMenuBar = JMenuBar() + val menus = sciview.scijavaContext?.getService(MenuService::class.java) + ?: throw IllegalStateException("MenuService not available") + SwingJMenuBarCreator().createMenus(menus.getMenu("SciView"), swingMenuBar) + + val bar = ProgressPie() + bar.value = 0.0 + bar.minimumSize = Dimension(30, 30) + bar.maximumSize = Dimension(30, 30) + bar.preferredSize = Dimension(30, 30) + val progressLabel = JLabel("") + progressLabel.horizontalAlignment = SwingConstants.RIGHT + swingMenuBar.add(Box.createHorizontalGlue()) + swingMenuBar.add(progressLabel) + swingMenuBar.add(bar) + frame.jMenuBar = swingMenuBar + + sciview.taskManager.update = { current -> + if (current != null) { + progressLabel.text = "${current.source}: ${current.status} " + bar.value = current.completion.toDouble() + } else { + progressLabel.text = "" + bar.value = 0.0 + } + + bar.repaint() + } + sceneryJPanel.isVisible = true + nodePropertyEditor.component // Initialize node property panel + + val inspectorTree = nodePropertyEditor.tree + inspectorTree.toggleClickCount = 0 // This disables expanding menus on double click + val inspectorProperties = nodePropertyEditor.props + + val container = JPanel(CardLayout()) + + var propsPane = JScrollPane(inspectorProperties) + var treePane = JScrollPane(inspectorTree) + propsPane.verticalScrollBar.unitIncrement = 16 + treePane.verticalScrollBar.unitIncrement = 16 + inspector = JSplitPane(JSplitPane.VERTICAL_SPLIT, // + treePane, + propsPane) + inspector.dividerLocation = sciview.windowHeight / 3 + inspector.isContinuousLayout = true + inspector.border = BorderFactory.createEmptyBorder() + inspector.dividerSize = 4 + inspector.name = "Inspector" + container.add(inspector, "Inspector") + + // We need to get the surface scale here before initialising scenery's renderer, as + // the information is needed already at initialisation time. + val dt = frame.graphicsConfiguration.defaultTransform + val surfaceScale = Vector2f(dt.scaleX.toFloat(), dt.scaleY.toFloat()) + sciview.getScenerySettings().set("Renderer.SurfaceScale", surfaceScale) + interpreterPane = REPLPane(sciview.scijavaContext) + interpreterPane.component.border = BorderFactory.createEmptyBorder() + interpreterPane.component.name = "REPL" + container.add(interpreterPane.component, "REPL") + thread { + initializeInterpreter() } + mainSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + sceneryJPanel, + container + ) + mainSplitPane.dividerLocation = frame.width + mainSplitPane.border = BorderFactory.createEmptyBorder() + mainSplitPane.dividerSize = 4 + mainSplitPane.resizeWeight = 1.0 + mainSplitPane.rightComponent = null - bar.repaint() - } - sceneryJPanel.isVisible = true - nodePropertyEditor.component // Initialize node property panel - - val inspectorTree = nodePropertyEditor.tree - inspectorTree.toggleClickCount = 0 // This disables expanding menus on double click - val inspectorProperties = nodePropertyEditor.props - - val container = JPanel(CardLayout()) - - var propsPane = JScrollPane(inspectorProperties) - var treePane = JScrollPane(inspectorTree) - propsPane.verticalScrollBar.unitIncrement = 16 - treePane.verticalScrollBar.unitIncrement = 16 - inspector = JSplitPane(JSplitPane.VERTICAL_SPLIT, // - treePane, - propsPane) - inspector.dividerLocation = sciview.windowHeight / 3 - inspector.isContinuousLayout = true - inspector.border = BorderFactory.createEmptyBorder() - inspector.dividerSize = 1 - inspector.name = "Inspector" - container.add(inspector, "Inspector") - - // We need to get the surface scale here before initialising scenery's renderer, as - // the information is needed already at initialisation time. - val dt = frame.graphicsConfiguration.defaultTransform - val surfaceScale = Vector2f(dt.scaleX.toFloat(), dt.scaleY.toFloat()) - sciview.getScenerySettings().set("Renderer.SurfaceScale", surfaceScale) - interpreterPane = REPLPane(sciview.scijavaContext) - interpreterPane.component.border = BorderFactory.createEmptyBorder() - interpreterPane.component.name = "REPL" - container.add(interpreterPane.component, "REPL") - initializeInterpreter() - mainSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - sceneryJPanel, - container - ) - mainSplitPane.dividerLocation = frame.width - mainSplitPane.border = BorderFactory.createEmptyBorder() - mainSplitPane.dividerSize = 1 - mainSplitPane.resizeWeight = 0.5 - mainSplitPane.rightComponent = null - - val toolbar = JToolBar() - toolbar.orientation = SwingConstants.VERTICAL - - val inspectorIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("toolbox.png"), 16, 16) - val inspectorButton = JToggleButton() - inspectorButton.toolTipText = "Inspector" - - val inspectorAction = object: AbstractAction("Inspector", inspectorIcon) { - override fun actionPerformed(e: ActionEvent) { - container.toggleSidebarComponent(inspector, toolbar, inspectorButton, e) + val toolbar = JToolBar() + toolbar.orientation = SwingConstants.VERTICAL + + val inspectorIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("toolbox.png"), 16, 16) + val inspectorButton = JToggleButton() + inspectorButton.toolTipText = "Inspector" + + val inspectorAction = object : AbstractAction("Inspector", inspectorIcon) { + override fun actionPerformed(e: ActionEvent) { + container.toggleSidebarComponent(inspector, toolbar, inspectorButton, e) + } } - } - defaultSidebarAction = { container.toggleSidebarComponent(inspector, toolbar, inspectorButton, null) } + defaultSidebarAction = { container.toggleSidebarComponent(inspector, toolbar, inspectorButton, null) } - inspectorButton.action = inspectorAction - inspectorButton.icon = inspectorIcon - inspectorButton.hideActionText = true + inspectorButton.action = inspectorAction + inspectorButton.icon = inspectorIcon + inspectorButton.hideActionText = true - val replIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("terminal.png"), 16, 16) - val replButton = JToggleButton() - replButton.toolTipText = "Script Interpreter" + val replIcon = Utils.getScaledImageIcon(SciView::class.java.getResource("terminal.png"), 16, 16) + val replButton = JToggleButton() + replButton.toolTipText = "Script Interpreter" - val replAction = object: AbstractAction("REPL", replIcon) { - override fun actionPerformed(e: ActionEvent) { - container.toggleSidebarComponent(interpreterPane.component, toolbar, replButton, e) + val replAction = object : AbstractAction("REPL", replIcon) { + override fun actionPerformed(e: ActionEvent) { + container.toggleSidebarComponent(interpreterPane.component, toolbar, replButton, e) + } } - } - replButton.action = replAction - replButton.icon = replIcon - replButton.hideActionText = true - - toolbar.add(inspectorButton) - toolbar.add(replButton) - - //frame.add(mainSplitPane, BorderLayout.CENTER); - frame.add(mainSplitPane, BorderLayout.CENTER) - frame.add(toolbar, BorderLayout.EAST) - frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE - frame.addWindowListener(object : WindowAdapter() { - override fun windowClosing(e: WindowEvent) { - logger.debug("Closing SciView window.") - close() - sciview.scijavaContext?.service(SciViewService::class.java)?.close(sciview) - sciview.isClosed = true - } - }) - - frame.isVisible = true - glassPane.repaint() - - sciview.sceneryPanel[0] = sceneryJPanel - val renderer = Renderer.createRenderer( - sciview.hub, - sciview.applicationName, - sciview.currentScene, - sciview.windowWidth, - sciview.windowHeight, - sciview.sceneryPanel[0] - ) - - sciview.setRenderer(renderer) - sciview.hub.add(SceneryElement.Renderer, renderer) - sciview.reset() - - SwingUtilities.invokeLater { - try { - while (!sciview.getSceneryRenderer()!!.firstImageReady) { - logger.debug("Waiting for renderer initialisation") - Thread.sleep(300) + replButton.action = replAction + replButton.icon = replIcon + replButton.hideActionText = true + + toolbar.add(inspectorButton) + toolbar.add(replButton) + + //frame.add(mainSplitPane, BorderLayout.CENTER); + frame.add(mainSplitPane, BorderLayout.CENTER) + frame.add(toolbar, BorderLayout.EAST) + frame.defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE + frame.addWindowListener(object : WindowAdapter() { + override fun windowClosing(e: WindowEvent) { + logger.debug("Closing SciView window.") + close() + sciview.scijavaContext?.service(SciViewService::class.java)?.close(sciview) + sciview.isClosed = true } - Thread.sleep(200) - } catch (e: InterruptedException) { - logger.error("Renderer construction interrupted.") - } - nodePropertyEditor.rebuildTree() - logger.info("Done initializing SciView") + }) + + frame.isVisible = true + glassPane.repaint() + + sciview.sceneryPanel[0] = sceneryJPanel + val renderer = Renderer.createRenderer( + sciview.hub, + sciview.applicationName, + sciview.currentScene, + sciview.windowWidth, + sciview.windowHeight, + sciview.sceneryPanel[0] + ) + + sciview.setRenderer(renderer) + sciview.hub.add(SceneryElement.Renderer, renderer) + sciview.reset() + + SwingUtilities.invokeLater { + try { + while (!sciview.getSceneryRenderer()!!.firstImageReady) { + logger.debug("Waiting for renderer initialisation") + Thread.sleep(300) + } + Thread.sleep(200) + } catch (e: InterruptedException) { + logger.error("Renderer construction interrupted.") + } + nodePropertyEditor.rebuildTree() + logger.info("Done initializing SciView") - // subscribe to Node{Added, Removed, Changed} events, happens automatically + // subscribe to Node{Added, Removed, Changed} events, happens automatically // eventService!!.subscribe(this) - sceneryJPanel.isVisible = true + sceneryJPanel.isVisible = true - // install hook to keep inspector updated on external changes (scripting, etc) - sciview.currentScene.onNodePropertiesChanged["updateInspector"] = { node: Node -> - if (node === nodePropertyEditor.currentNode) { - nodePropertyEditor.updateProperties(node) + // install hook to keep inspector updated on external changes (scripting, etc) + sciview.currentScene.onNodePropertiesChanged["updateInspector"] = { node: Node -> + if (node === nodePropertyEditor.currentNode) { + nodePropertyEditor.updateProperties(node) + } } - } - // Enable push rendering by default - renderer.pushMode = true - sciview.camera!!.setPosition(1.65, 1) - glassPane.isVisible = false + // Enable push rendering by default + renderer.pushMode = true + sciview.camera!!.setPosition(1.65, 1) + glassPane.isVisible = false + + sceneryJPanel.minimumSize = Dimension(256, 256) + } + } - sceneryJPanel.minimumSize = Dimension(256, 256) + if(SwingUtilities.isEventDispatchThread()) { + initializer.run() + } else { + SwingUtilities.invokeAndWait(initializer) } } From 414505f0dc8faa3dd519fba71c61943c74ae94f7 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 16:18:21 +0200 Subject: [PATCH 15/29] Gradle: Bump to latest staging repo for scenery --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 996f56db..e6b98708 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1221") + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } From b815e4dadfb91892e0aee6dfd8310b4db74e0cdd Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 16 Jun 2023 16:20:07 +0200 Subject: [PATCH 16/29] SwingNodePropertyEditor: Add TransferFunctionEditor for volumes --- src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt index 83f517e4..4e4a995a 100644 --- a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt +++ b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt @@ -32,6 +32,8 @@ import com.intellij.ui.components.JBPanel import graphics.scenery.Camera import graphics.scenery.Node import graphics.scenery.Scene +import graphics.scenery.volumes.TransferFunctionEditor +import graphics.scenery.volumes.Volume import net.miginfocom.swing.MigLayout import org.joml.Quaternionf import org.joml.Vector3f @@ -340,6 +342,13 @@ class SwingNodePropertyEditor(private val sciView: SciView) : UIComponent Date: Wed, 21 Jun 2023 14:12:25 +0200 Subject: [PATCH 17/29] Gradle: Bump scenery staging repo to latest version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index e6b98708..6b7175e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1223") maven("https://maven.scijava.org/content/groups/public") } From 161d744158c58742d0cb337b64c9ec6c3f6a472b Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Wed, 21 Jun 2023 14:38:15 +0200 Subject: [PATCH 18/29] Gradle: Use correct pom-scijava version when building Maven POM --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6b7175e8..e70c11bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -166,7 +166,7 @@ tasks { val parent = asNode().appendNode("parent") parent.appendNode("groupId", "org.scijava") parent.appendNode("artifactId", "pom-scijava") - parent.appendNode("version", "31.1.0") + parent.appendNode("version", "35.1.1") parent.appendNode("relativePath") val repositories = asNode().appendNode("repositories") From 7f7f57e504199055fdc477b9bbc4aaca4376bf77 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 7 Jul 2023 11:24:08 +0200 Subject: [PATCH 19/29] SwingGroupingInputHarvester: Indicate open/closed groups --- src/main/kotlin/sc/iview/ui/SwingGroupingInputHarvester.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/sc/iview/ui/SwingGroupingInputHarvester.kt b/src/main/kotlin/sc/iview/ui/SwingGroupingInputHarvester.kt index 2bd7f3ee..94b2672f 100644 --- a/src/main/kotlin/sc/iview/ui/SwingGroupingInputHarvester.kt +++ b/src/main/kotlin/sc/iview/ui/SwingGroupingInputHarvester.kt @@ -95,7 +95,7 @@ class SwingGroupingInputHarvester : SwingInputHarvester() { if(panel.component.isVisible) { label.text = "▼ ${group.key}" } else { - label.text = "▶ ${group.key}" + label.text = """ ${group.key}""" } inputPanel.component.revalidate() } From edb830972e2fd6a8b0d7f3220993c6b214cd6aa6 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 7 Jul 2023 11:24:41 +0200 Subject: [PATCH 20/29] SwingNodePropertyEditor: Try to fix layout for TransferFunctionEditor --- src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt index 4e4a995a..b9f05517 100644 --- a/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt +++ b/src/main/kotlin/sc/iview/ui/SwingNodePropertyEditor.kt @@ -336,16 +336,18 @@ class SwingNodePropertyEditor(private val sciView: SciView) : UIComponent Date: Fri, 14 Jul 2023 14:24:41 +0200 Subject: [PATCH 21/29] Gradle: Remove staging repo to point to scenery 0.9.0 release --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index e70c11bd..c2753c22 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,6 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1223") maven("https://maven.scijava.org/content/groups/public") } From d50e2a8e920ace13b09dd0ed9e4f02646d8dd443 Mon Sep 17 00:00:00 2001 From: Ulrik Guenther Date: Fri, 14 Jul 2023 14:37:58 +0200 Subject: [PATCH 22/29] Gradle: Manage scijava parent POM, Kotlin, and Dokka versions in gradle.properties --- build.gradle.kts | 18 +++++++++--------- gradle.properties | 3 +++ settings.gradle.kts | 16 +++++++++++----- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index c2753c22..c30cd305 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,15 +4,13 @@ import java.net.URL import sciview.* plugins { - val ktVersion = "1.8.22" - val dokkaVersion = "1.8.20" - java - kotlin("jvm") version ktVersion - kotlin("kapt") version ktVersion + // Kotlin/Dokka versions are managed in gradle.properties + kotlin("jvm") + kotlin("kapt") sciview.publish sciview.sign - id("org.jetbrains.dokka") version dokkaVersion + id("org.jetbrains.dokka") jacoco `maven-publish` `java-library` @@ -34,8 +32,9 @@ repositories { } dependencies { - val ktVersion = "1.8.22" - implementation(platform("org.scijava:pom-scijava:35.1.1")) + val scijavaParentPomVersion = project.properties["scijavaParentPOMVersion"] + val ktVersion = project.properties["kotlinVersion"] + implementation(platform("org.scijava:pom-scijava:$scijavaParentPomVersion")) // Graphics dependencies @@ -155,6 +154,7 @@ tasks { } withType().configureEach { + val scijavaParentPomVersion = project.properties["scijavaParentPOMVersion"] val matcher = Regex("""generatePomFileFor(\w+)Publication""").matchEntire(name) val publicationName = matcher?.let { it.groupValues[1] } @@ -165,7 +165,7 @@ tasks { val parent = asNode().appendNode("parent") parent.appendNode("groupId", "org.scijava") parent.appendNode("artifactId", "pom-scijava") - parent.appendNode("version", "35.1.1") + parent.appendNode("version", "$scijavaParentPomVersion") parent.appendNode("relativePath") val repositories = asNode().appendNode("repositories") diff --git a/gradle.properties b/gradle.properties index bedcd1be..b762473c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,6 @@ org.gradle.jvmargs=-XX:MaxMetaspaceSize=2g org.gradle.caching=true jvmTarget=11 #useLocalScenery=true +kotlinVersion=1.8.22 +dokkaVersion=1.8.20 +scijavaParentPOMVersion=35.1.1 diff --git a/settings.gradle.kts b/settings.gradle.kts index 1bab6a17..48e3d4a5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,15 +1,21 @@ - pluginManagement { + val kotlinVersion: String by settings + val dokkaVersion: String by settings + + plugins { + kotlin("jvm") version kotlinVersion + kotlin("kapt") version kotlinVersion + id("org.jetbrains.dokka") version dokkaVersion + + id("com.github.johnrengelman.shadow") version "8.1.1" + } + repositories { gradlePluginPortal() maven("https://raw.githubusercontent.com/kotlin-graphics/mary/master") } } -//plugins { -// id("sciJava.catalogs") version "30.0.0+66" -//} - rootProject.name = "sciview" gradle.rootProject { From 84673ecb6970f9280db09e03fd13ed8d7d41e5f9 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Tue, 13 Jun 2023 07:01:20 -0400 Subject: [PATCH 23/29] [wip] OpenOrganelle demo, super not working yet --- build.gradle.kts | 8 + .../kotlin/sc/iview/commands/MenuWeights.kt | 1 + .../commands/demo/advanced/OpenOrganelle.kt | 256 ++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/build.gradle.kts b/build.gradle.kts index c30cd305..ed985e91 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -113,6 +113,14 @@ dependencies { // implementation(n5.imglib2) implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-hdf5") + implementation("org.janelia.saalfeldlab:n5-ij:3.2.4-SNAPSHOT") + implementation("org.janelia.saalfeldlab:n5-imglib2:5.0.0") + implementation("org.janelia.saalfeldlab:n5-viewer_fiji:5.3.0") + //implementation("com.github.saalfeldlab:n5-viewer:ec0b177") + implementation("org.janelia.saalfeldlab:n5-aws-s3") + implementation("org.janelia.saalfeldlab:n5-google-cloud") + implementation("org.janelia.saalfeldlab:n5-blosc") + implementation("org.janelia.saalfeldlab:n5-zarr") implementation("sc.fiji:spim_data") implementation(platform(kotlin("bom"))) diff --git a/src/main/kotlin/sc/iview/commands/MenuWeights.kt b/src/main/kotlin/sc/iview/commands/MenuWeights.kt index 5e224bdf..c3d9eaef 100644 --- a/src/main/kotlin/sc/iview/commands/MenuWeights.kt +++ b/src/main/kotlin/sc/iview/commands/MenuWeights.kt @@ -115,6 +115,7 @@ object MenuWeights { const val DEMO_ADVANCED_CREMI = 1.0 const val DEMO_ADVANCED_BDVSLICING = 2.0 const val DEMO_ADVANCED_MESHTEXTURE = 3.0 + const val DEMO_ADVANCED_OPENORGANELLE = 4.0 // Help const val HELP_HELP = 0.0 const val HELP_ABOUT = 200.0 diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt new file mode 100644 index 00000000..da14037a --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt @@ -0,0 +1,256 @@ +package sc.iview.commands.demo.advanced + +import graphics.scenery.Origin +import graphics.scenery.utils.extensions.xyz +import graphics.scenery.volumes.Colormap +import graphics.scenery.volumes.TransferFunction +import net.imagej.lut.LUTService +import net.imagej.mesh.Mesh +import net.imagej.mesh.Meshes +import net.imagej.ops.OpService +import net.imglib2.RandomAccessibleInterval +import net.imglib2.cache.img.CachedCellImg +import net.imglib2.roi.labeling.ImgLabeling +import net.imglib2.roi.labeling.LabelRegions +import net.imglib2.type.NativeType +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.RealType +import net.imglib2.view.Views +import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer +import org.janelia.saalfeldlab.n5.N5Reader +import org.janelia.saalfeldlab.n5.N5TreeNode +import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets +import org.janelia.saalfeldlab.n5.ij.N5Factory +import org.janelia.saalfeldlab.n5.ij.N5Importer +import org.janelia.saalfeldlab.n5.imglib2.N5Utils +import org.janelia.saalfeldlab.n5.metadata.* +import org.janelia.saalfeldlab.n5.ui.DataSelection +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 sc.iview.commands.demo.basic.VolumeRenderDemo +import sc.iview.process.MeshConverter +import java.io.File +import java.io.IOException +import java.util.* +import java.util.concurrent.Executors + + +@Plugin(type = Command::class, + label = "OpenOrganelle demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) +class OpenOrganelle : Command { + @Parameter + private lateinit var ui: UIService + + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var ops: OpService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + /* + * TODO + * + * https://openorganelle.janelia.org/datasets/jrc_mus-kidney + * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 + * + */ + + internal class DefaultLabelIterator : MutableIterator { + private var i = 0L + override fun hasNext(): Boolean { + return i < Long.MAX_VALUE + } + + override fun next(): Long { + return i++ + } + + override fun remove() { + throw UnsupportedOperationException() + } + } + + /** + * 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("OpenOrganelle", "Loading dataset") + + val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") + + // Read the EM volume + task.status = "Reading image volume" + //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") + log.info("Start Reading") + val nai = readMultiscaleN5() + + log.info("Done Reading") + + if (nai == null) { + log.error("Could not read data") + return + } +// val raiVolume = nai.third +// val cursor = Views.iterable(raiVolume).localizingCursor() +// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { +// cursor.fwd() +// cursor.get().set(0) +// } +// + val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) +// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) + +// sciview.addVolume(nai) { +// origin = Origin.FrontBottomLeft +// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) +// 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(20.0, 220.0) +// colormap = Colormap.fromColorTable(colormapVolume) +// } + + // Read the labels volume + task.status = "Reading labels volume" + val labels = readMultiscaleN5() + + task.status = "Creating labeling" + task.completion = 10.0f +// val rai = nai.second +// log.info("Got ${nai.first.size} labels") + + // let's extract some neurons here + log.info("Creating labeling ...") + + //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() +// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) +// log.info("Creating regions...") +// val regions = LabelRegions(labeling) +// log.info("Created ${regions.count()} regions") +// +// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } +// +// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") +// +// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> +// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") +// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" +// +// // ui.show(region) +// // Generate the mesh with imagej-ops +// val m: Mesh = Meshes.marchingCubes(region); +// +// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") +// // Convert the mesh into a scenery mesh for visualization +// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) +// sciview.addNode(mesh) { +// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) +// ifMaterial { +// diffuse = +// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() +// .xyz() +// roughness = 0.0f +// } +// name = "Neuron $i" +// } +// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f +// task.completion = completion +// } +// +// task.completion = 100.0f + } + + + + fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", + multiscaleBaseDataset: String = "/labels/empanada-mito_seg", + scale: Double = 1.0): CachedCellImg, *>? { + // set up the n5 reader + + log.info("Opening reader") + var n5: N5Reader = N5Factory().openReader(n5root) + // parse the metadata so bdv knows how to display the scales + val importers = Arrays.asList>(*N5Importer.PARSERS) + val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) + log.info("Dataset discoverer") + val parsers = N5DatasetDiscoverer( + n5, + Executors.newSingleThreadExecutor(), + importers, + groupParsers + ) + + log.info("Dataset discoverer done") + + // get the particular metadata we care above + var root = parsers.discoverAndParseRecursive("") + val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata + + var datasetToOpen = multiscaleMetadata.path + + log.info("Opening image") + + var img = N5Utils.openVolatile(n5, datasetToOpen) + + log.info("Image opened") + + // run n5 viewer + //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); + + + return img + } + + + private fun Int.toRGBColor(): Vector4f { + val a = ARGBType.alpha(this) / 255.0f + val r = ARGBType.red(this) / 255.0f + val g = ARGBType.green(this) / 255.0f + val b = ARGBType.blue(this) / 255.0f + + return Vector4f(r, g, b, a) + } + + + 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(OpenOrganelle::class.java, true, argmap) + } + } +} \ No newline at end of file From f30360515df7dd2d6a232b83536de345fadee7e0 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:06:05 -0400 Subject: [PATCH 24/29] Switch to main repo from staging --- .../commands/demo/advanced/OpenOrganelle.kt | 256 ------------------ 1 file changed, 256 deletions(-) delete mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt deleted file mode 100644 index da14037a..00000000 --- a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt +++ /dev/null @@ -1,256 +0,0 @@ -package sc.iview.commands.demo.advanced - -import graphics.scenery.Origin -import graphics.scenery.utils.extensions.xyz -import graphics.scenery.volumes.Colormap -import graphics.scenery.volumes.TransferFunction -import net.imagej.lut.LUTService -import net.imagej.mesh.Mesh -import net.imagej.mesh.Meshes -import net.imagej.ops.OpService -import net.imglib2.RandomAccessibleInterval -import net.imglib2.cache.img.CachedCellImg -import net.imglib2.roi.labeling.ImgLabeling -import net.imglib2.roi.labeling.LabelRegions -import net.imglib2.type.NativeType -import net.imglib2.type.numeric.ARGBType -import net.imglib2.type.numeric.RealType -import net.imglib2.view.Views -import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer -import org.janelia.saalfeldlab.n5.N5Reader -import org.janelia.saalfeldlab.n5.N5TreeNode -import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets -import org.janelia.saalfeldlab.n5.ij.N5Factory -import org.janelia.saalfeldlab.n5.ij.N5Importer -import org.janelia.saalfeldlab.n5.imglib2.N5Utils -import org.janelia.saalfeldlab.n5.metadata.* -import org.janelia.saalfeldlab.n5.ui.DataSelection -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 sc.iview.commands.demo.basic.VolumeRenderDemo -import sc.iview.process.MeshConverter -import java.io.File -import java.io.IOException -import java.util.* -import java.util.concurrent.Executors - - -@Plugin(type = Command::class, - label = "OpenOrganelle demo", - menuRoot = "SciView", - menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), - Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), - Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) -class OpenOrganelle : Command { - @Parameter - private lateinit var ui: UIService - - @Parameter - private lateinit var log: LogService - - @Parameter - private lateinit var ops: OpService - - @Parameter - private lateinit var sciview: SciView - - @Parameter - private lateinit var lut: LUTService - - /* - * TODO - * - * https://openorganelle.janelia.org/datasets/jrc_mus-kidney - * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 - * - */ - - internal class DefaultLabelIterator : MutableIterator { - private var i = 0L - override fun hasNext(): Boolean { - return i < Long.MAX_VALUE - } - - override fun next(): Long { - return i++ - } - - override fun remove() { - throw UnsupportedOperationException() - } - } - - /** - * 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("OpenOrganelle", "Loading dataset") - - val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") - - // Read the EM volume - task.status = "Reading image volume" - //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") - log.info("Start Reading") - val nai = readMultiscaleN5() - - log.info("Done Reading") - - if (nai == null) { - log.error("Could not read data") - return - } -// val raiVolume = nai.third -// val cursor = Views.iterable(raiVolume).localizingCursor() -// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { -// cursor.fwd() -// cursor.get().set(0) -// } -// - val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) -// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) - -// sciview.addVolume(nai) { -// origin = Origin.FrontBottomLeft -// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) -// 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(20.0, 220.0) -// colormap = Colormap.fromColorTable(colormapVolume) -// } - - // Read the labels volume - task.status = "Reading labels volume" - val labels = readMultiscaleN5() - - task.status = "Creating labeling" - task.completion = 10.0f -// val rai = nai.second -// log.info("Got ${nai.first.size} labels") - - // let's extract some neurons here - log.info("Creating labeling ...") - - //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() -// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) -// log.info("Creating regions...") -// val regions = LabelRegions(labeling) -// log.info("Created ${regions.count()} regions") -// -// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } -// -// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") -// -// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> -// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") -// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" -// -// // ui.show(region) -// // Generate the mesh with imagej-ops -// val m: Mesh = Meshes.marchingCubes(region); -// -// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") -// // Convert the mesh into a scenery mesh for visualization -// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) -// sciview.addNode(mesh) { -// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) -// ifMaterial { -// diffuse = -// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() -// .xyz() -// roughness = 0.0f -// } -// name = "Neuron $i" -// } -// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f -// task.completion = completion -// } -// -// task.completion = 100.0f - } - - - - fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", - multiscaleBaseDataset: String = "/labels/empanada-mito_seg", - scale: Double = 1.0): CachedCellImg, *>? { - // set up the n5 reader - - log.info("Opening reader") - var n5: N5Reader = N5Factory().openReader(n5root) - // parse the metadata so bdv knows how to display the scales - val importers = Arrays.asList>(*N5Importer.PARSERS) - val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) - log.info("Dataset discoverer") - val parsers = N5DatasetDiscoverer( - n5, - Executors.newSingleThreadExecutor(), - importers, - groupParsers - ) - - log.info("Dataset discoverer done") - - // get the particular metadata we care above - var root = parsers.discoverAndParseRecursive("") - val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata - - var datasetToOpen = multiscaleMetadata.path - - log.info("Opening image") - - var img = N5Utils.openVolatile(n5, datasetToOpen) - - log.info("Image opened") - - // run n5 viewer - //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); - - - return img - } - - - private fun Int.toRGBColor(): Vector4f { - val a = ARGBType.alpha(this) / 255.0f - val r = ARGBType.red(this) / 255.0f - val g = ARGBType.green(this) / 255.0f - val b = ARGBType.blue(this) / 255.0f - - return Vector4f(r, g, b, a) - } - - - 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(OpenOrganelle::class.java, true, argmap) - } - } -} \ No newline at end of file From ca750c7d6d26dbc8ca85b2a3b0830c71e1aa45e6 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:10:43 -0400 Subject: [PATCH 25/29] Revert "Switch to main repo from staging" This reverts commit 977e9aa1a9f7de89e131060a1b5cbe2cb67b3e38. --- build.gradle.kts | 1 + .../commands/demo/advanced/OpenOrganelle.kt | 256 ++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/build.gradle.kts b/build.gradle.kts index ed985e91..cd66f8e7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,6 +28,7 @@ repositories { mavenLocal() } mavenCentral() + maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt new file mode 100644 index 00000000..da14037a --- /dev/null +++ b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt @@ -0,0 +1,256 @@ +package sc.iview.commands.demo.advanced + +import graphics.scenery.Origin +import graphics.scenery.utils.extensions.xyz +import graphics.scenery.volumes.Colormap +import graphics.scenery.volumes.TransferFunction +import net.imagej.lut.LUTService +import net.imagej.mesh.Mesh +import net.imagej.mesh.Meshes +import net.imagej.ops.OpService +import net.imglib2.RandomAccessibleInterval +import net.imglib2.cache.img.CachedCellImg +import net.imglib2.roi.labeling.ImgLabeling +import net.imglib2.roi.labeling.LabelRegions +import net.imglib2.type.NativeType +import net.imglib2.type.numeric.ARGBType +import net.imglib2.type.numeric.RealType +import net.imglib2.view.Views +import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer +import org.janelia.saalfeldlab.n5.N5Reader +import org.janelia.saalfeldlab.n5.N5TreeNode +import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets +import org.janelia.saalfeldlab.n5.ij.N5Factory +import org.janelia.saalfeldlab.n5.ij.N5Importer +import org.janelia.saalfeldlab.n5.imglib2.N5Utils +import org.janelia.saalfeldlab.n5.metadata.* +import org.janelia.saalfeldlab.n5.ui.DataSelection +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 sc.iview.commands.demo.basic.VolumeRenderDemo +import sc.iview.process.MeshConverter +import java.io.File +import java.io.IOException +import java.util.* +import java.util.concurrent.Executors + + +@Plugin(type = Command::class, + label = "OpenOrganelle demo", + menuRoot = "SciView", + menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), + Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), + Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) +class OpenOrganelle : Command { + @Parameter + private lateinit var ui: UIService + + @Parameter + private lateinit var log: LogService + + @Parameter + private lateinit var ops: OpService + + @Parameter + private lateinit var sciview: SciView + + @Parameter + private lateinit var lut: LUTService + + /* + * TODO + * + * https://openorganelle.janelia.org/datasets/jrc_mus-kidney + * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 + * + */ + + internal class DefaultLabelIterator : MutableIterator { + private var i = 0L + override fun hasNext(): Boolean { + return i < Long.MAX_VALUE + } + + override fun next(): Long { + return i++ + } + + override fun remove() { + throw UnsupportedOperationException() + } + } + + /** + * 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("OpenOrganelle", "Loading dataset") + + val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") + + // Read the EM volume + task.status = "Reading image volume" + //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") + log.info("Start Reading") + val nai = readMultiscaleN5() + + log.info("Done Reading") + + if (nai == null) { + log.error("Could not read data") + return + } +// val raiVolume = nai.third +// val cursor = Views.iterable(raiVolume).localizingCursor() +// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { +// cursor.fwd() +// cursor.get().set(0) +// } +// + val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) +// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) + +// sciview.addVolume(nai) { +// origin = Origin.FrontBottomLeft +// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) +// 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(20.0, 220.0) +// colormap = Colormap.fromColorTable(colormapVolume) +// } + + // Read the labels volume + task.status = "Reading labels volume" + val labels = readMultiscaleN5() + + task.status = "Creating labeling" + task.completion = 10.0f +// val rai = nai.second +// log.info("Got ${nai.first.size} labels") + + // let's extract some neurons here + log.info("Creating labeling ...") + + //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() +// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) +// log.info("Creating regions...") +// val regions = LabelRegions(labeling) +// log.info("Created ${regions.count()} regions") +// +// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } +// +// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") +// +// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> +// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") +// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" +// +// // ui.show(region) +// // Generate the mesh with imagej-ops +// val m: Mesh = Meshes.marchingCubes(region); +// +// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") +// // Convert the mesh into a scenery mesh for visualization +// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) +// sciview.addNode(mesh) { +// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) +// ifMaterial { +// diffuse = +// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() +// .xyz() +// roughness = 0.0f +// } +// name = "Neuron $i" +// } +// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f +// task.completion = completion +// } +// +// task.completion = 100.0f + } + + + + fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", + multiscaleBaseDataset: String = "/labels/empanada-mito_seg", + scale: Double = 1.0): CachedCellImg, *>? { + // set up the n5 reader + + log.info("Opening reader") + var n5: N5Reader = N5Factory().openReader(n5root) + // parse the metadata so bdv knows how to display the scales + val importers = Arrays.asList>(*N5Importer.PARSERS) + val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) + log.info("Dataset discoverer") + val parsers = N5DatasetDiscoverer( + n5, + Executors.newSingleThreadExecutor(), + importers, + groupParsers + ) + + log.info("Dataset discoverer done") + + // get the particular metadata we care above + var root = parsers.discoverAndParseRecursive("") + val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata + + var datasetToOpen = multiscaleMetadata.path + + log.info("Opening image") + + var img = N5Utils.openVolatile(n5, datasetToOpen) + + log.info("Image opened") + + // run n5 viewer + //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); + + + return img + } + + + private fun Int.toRGBColor(): Vector4f { + val a = ARGBType.alpha(this) / 255.0f + val r = ARGBType.red(this) / 255.0f + val g = ARGBType.green(this) / 255.0f + val b = ARGBType.blue(this) / 255.0f + + return Vector4f(r, g, b, a) + } + + + 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(OpenOrganelle::class.java, true, argmap) + } + } +} \ No newline at end of file From 79576f4deb033d26f0a0c8f8eab5bb5f79497b16 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:12:44 -0400 Subject: [PATCH 26/29] Remove OpenOrganelle demo that was accidentally added too early --- .../commands/demo/advanced/OpenOrganelle.kt | 256 ------------------ 1 file changed, 256 deletions(-) delete mode 100644 src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt diff --git a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt b/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt deleted file mode 100644 index da14037a..00000000 --- a/src/main/kotlin/sc/iview/commands/demo/advanced/OpenOrganelle.kt +++ /dev/null @@ -1,256 +0,0 @@ -package sc.iview.commands.demo.advanced - -import graphics.scenery.Origin -import graphics.scenery.utils.extensions.xyz -import graphics.scenery.volumes.Colormap -import graphics.scenery.volumes.TransferFunction -import net.imagej.lut.LUTService -import net.imagej.mesh.Mesh -import net.imagej.mesh.Meshes -import net.imagej.ops.OpService -import net.imglib2.RandomAccessibleInterval -import net.imglib2.cache.img.CachedCellImg -import net.imglib2.roi.labeling.ImgLabeling -import net.imglib2.roi.labeling.LabelRegions -import net.imglib2.type.NativeType -import net.imglib2.type.numeric.ARGBType -import net.imglib2.type.numeric.RealType -import net.imglib2.view.Views -import org.janelia.saalfeldlab.n5.N5DatasetDiscoverer -import org.janelia.saalfeldlab.n5.N5Reader -import org.janelia.saalfeldlab.n5.N5TreeNode -import org.janelia.saalfeldlab.n5.bdv.MultiscaleDatasets -import org.janelia.saalfeldlab.n5.ij.N5Factory -import org.janelia.saalfeldlab.n5.ij.N5Importer -import org.janelia.saalfeldlab.n5.imglib2.N5Utils -import org.janelia.saalfeldlab.n5.metadata.* -import org.janelia.saalfeldlab.n5.ui.DataSelection -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 sc.iview.commands.demo.basic.VolumeRenderDemo -import sc.iview.process.MeshConverter -import java.io.File -import java.io.IOException -import java.util.* -import java.util.concurrent.Executors - - -@Plugin(type = Command::class, - label = "OpenOrganelle demo", - menuRoot = "SciView", - menu = [Menu(label = "Demo", weight = MenuWeights.DEMO), - Menu(label = "Advanced", weight = MenuWeights.DEMO_ADVANCED), - Menu(label = "OpenOrganelle Demo", weight = MenuWeights.DEMO_ADVANCED_OPENORGANELLE)]) -class OpenOrganelle : Command { - @Parameter - private lateinit var ui: UIService - - @Parameter - private lateinit var log: LogService - - @Parameter - private lateinit var ops: OpService - - @Parameter - private lateinit var sciview: SciView - - @Parameter - private lateinit var lut: LUTService - - /* - * TODO - * - * https://openorganelle.janelia.org/datasets/jrc_mus-kidney - * s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5 - * - */ - - internal class DefaultLabelIterator : MutableIterator { - private var i = 0L - override fun hasNext(): Boolean { - return i < Long.MAX_VALUE - } - - override fun next(): Long { - return i++ - } - - override fun remove() { - throw UnsupportedOperationException() - } - } - - /** - * 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("OpenOrganelle", "Loading dataset") - - val file = File("s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5") - - // Read the EM volume - task.status = "Reading image volume" - //val nai = readMultiscaleN5(file.canonicalPath, "em/fibsem-uint8") - log.info("Start Reading") - val nai = readMultiscaleN5() - - log.info("Done Reading") - - if (nai == null) { - log.error("Could not read data") - return - } -// val raiVolume = nai.third -// val cursor = Views.iterable(raiVolume).localizingCursor() -// while (cursor.hasNext() && cursor.getIntPosition(2) < 50) { -// cursor.fwd() -// cursor.get().set(0) -// } -// - val colormapVolume = lut.loadLUT(lut.findLUTs().get("Grays.lut")) -// val colormapNeurons = lut.loadLUT(lut.findLUTs().get("Fire.lut")) - -// sciview.addVolume(nai) { -// origin = Origin.FrontBottomLeft -// this.spatialOrNull()?.scale = Vector3f(0.08f, 0.08f, 5.0f) -// 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(20.0, 220.0) -// colormap = Colormap.fromColorTable(colormapVolume) -// } - - // Read the labels volume - task.status = "Reading labels volume" - val labels = readMultiscaleN5() - - task.status = "Creating labeling" - task.completion = 10.0f -// val rai = nai.second -// log.info("Got ${nai.first.size} labels") - - // let's extract some neurons here - log.info("Creating labeling ...") - - //val labels = (0..(nai.first.keys.maxOrNull()?.toInt() ?: 1)).toList() -// val labeling = ImgLabeling.fromImageAndLabels(rai, labels) -// log.info("Creating regions...") -// val regions = LabelRegions(labeling) -// log.info("Created ${regions.count()} regions") -// -// val largestNeuronLabels = nai.first.entries.sortedByDescending { p -> p.value }.take(50).shuffled().take(10).map { kv -> kv.key } -// -// log.info("Largest neuron labels are ${largestNeuronLabels.joinToString(",")}") -// -// regions.filter { largestNeuronLabels.contains(it.label.toLong() + 1L) }.forEachIndexed { i, region -> -// log.info("Meshing neuron ${i + 1}/${largestNeuronLabels.size} with label ${region.label}...") -// task.status = "Meshing neuron ${i + 1}/${largestNeuronLabels.size}" -// -// // ui.show(region) -// // Generate the mesh with imagej-ops -// val m: Mesh = Meshes.marchingCubes(region); -// -// log.info("Converting neuron ${i + 1}/${largestNeuronLabels.size} to scenery format...") -// // Convert the mesh into a scenery mesh for visualization -// val mesh = MeshConverter.toScenery(m, false, flipWindingOrder = true) -// sciview.addNode(mesh) { -// spatial().scale = Vector3f(0.01f, 0.01f, 0.06f) -// ifMaterial { -// diffuse = -// colormapNeurons.lookupARGB(0.0, 255.0, kotlin.random.Random.nextDouble(0.0, 255.0)).toRGBColor() -// .xyz() -// roughness = 0.0f -// } -// name = "Neuron $i" -// } -// val completion = 10.0f + ((i + 1) / largestNeuronLabels.size.toFloat()) * 90.0f -// task.completion = completion -// } -// -// task.completion = 100.0f - } - - - - fun readMultiscaleN5(n5root: String = "s3://janelia-cosem-datasets/jrc_mus-kidney/jrc_mus-kidney.n5", - multiscaleBaseDataset: String = "/labels/empanada-mito_seg", - scale: Double = 1.0): CachedCellImg, *>? { - // set up the n5 reader - - log.info("Opening reader") - var n5: N5Reader = N5Factory().openReader(n5root) - // parse the metadata so bdv knows how to display the scales - val importers = Arrays.asList>(*N5Importer.PARSERS) - val groupParsers = Arrays.asList>(*N5Importer.GROUP_PARSERS) - log.info("Dataset discoverer") - val parsers = N5DatasetDiscoverer( - n5, - Executors.newSingleThreadExecutor(), - importers, - groupParsers - ) - - log.info("Dataset discoverer done") - - // get the particular metadata we care above - var root = parsers.discoverAndParseRecursive("") - val multiscaleMetadata = root.childrenList()[0].childrenList()[0].metadata - - var datasetToOpen = multiscaleMetadata.path - - log.info("Opening image") - - var img = N5Utils.openVolatile(n5, datasetToOpen) - - log.info("Image opened") - - // run n5 viewer - //N5Viewer.exec(new DataSelection( n5, Collections.singletonList( multiscaleMetadata ))); - - - return img - } - - - private fun Int.toRGBColor(): Vector4f { - val a = ARGBType.alpha(this) / 255.0f - val r = ARGBType.red(this) / 255.0f - val g = ARGBType.green(this) / 255.0f - val b = ARGBType.blue(this) / 255.0f - - return Vector4f(r, g, b, a) - } - - - 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(OpenOrganelle::class.java, true, argmap) - } - } -} \ No newline at end of file From b5fc8247eb94624778d36cdf807931dc30e092a8 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:16:18 -0400 Subject: [PATCH 27/29] Remove OpenOrganelle menu weight --- src/main/kotlin/sc/iview/commands/MenuWeights.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/sc/iview/commands/MenuWeights.kt b/src/main/kotlin/sc/iview/commands/MenuWeights.kt index c3d9eaef..5e224bdf 100644 --- a/src/main/kotlin/sc/iview/commands/MenuWeights.kt +++ b/src/main/kotlin/sc/iview/commands/MenuWeights.kt @@ -115,7 +115,6 @@ object MenuWeights { const val DEMO_ADVANCED_CREMI = 1.0 const val DEMO_ADVANCED_BDVSLICING = 2.0 const val DEMO_ADVANCED_MESHTEXTURE = 3.0 - const val DEMO_ADVANCED_OPENORGANELLE = 4.0 // Help const val HELP_HELP = 0.0 const val HELP_ABOUT = 200.0 From 04bb7e4c32387c3df573ce3ebb8deefb18217e9e Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:17:02 -0400 Subject: [PATCH 28/29] Switch to main repo from staging --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index cd66f8e7..ed985e91 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,6 @@ repositories { mavenLocal() } mavenCentral() - maven("https://oss.sonatype.org/content/repositories/graphicsscenery-1222") maven("https://maven.scijava.org/content/groups/public") } From 18712ea8d80f7406c645de9a990b589fff51b4d2 Mon Sep 17 00:00:00 2001 From: Kyle Harrington Date: Fri, 14 Jul 2023 08:55:57 -0400 Subject: [PATCH 29/29] Remove explicit versioning of n5-ij --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index ed985e91..03f17660 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -113,7 +113,7 @@ dependencies { // implementation(n5.imglib2) implementation("org.janelia.saalfeldlab:n5") implementation("org.janelia.saalfeldlab:n5-hdf5") - implementation("org.janelia.saalfeldlab:n5-ij:3.2.4-SNAPSHOT") + implementation("org.janelia.saalfeldlab:n5-ij") implementation("org.janelia.saalfeldlab:n5-imglib2:5.0.0") implementation("org.janelia.saalfeldlab:n5-viewer_fiji:5.3.0") //implementation("com.github.saalfeldlab:n5-viewer:ec0b177")