Skip to content

Commit

Permalink
Minor changes to fix finding local maxima, adding info logs
Browse files Browse the repository at this point in the history
  • Loading branch information
smlpt committed Aug 26, 2024
1 parent fc6dd31 commit 4b4bd77
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 51 deletions.
47 changes: 21 additions & 26 deletions src/main/kotlin/sc/iview/commands/demo/advanced/EyeTrackingDemo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import graphics.scenery.attribute.material.Material
import graphics.scenery.primitives.Cylinder
import graphics.scenery.primitives.TextBoard
import graphics.scenery.volumes.RAIVolume
import sc.iview.commands.demo.animation.ParticleDemo
import kotlin.reflect.KClass

@Plugin(type = Command::class,
Expand Down Expand Up @@ -235,15 +236,17 @@ class EyeTrackingDemo: Command{

if(hedgehogs.visible) {
if(hedgehogVisibility == HedgehogVisibility.PerTimePoint) {
hedgehogs.children.forEach { hedgehog->
val hedgehog = hedgehog as InstancedNode
hedgehogs.children.forEach { hh ->
val hedgehog = hh as InstancedNode
hedgehog.instances.forEach {
it.visible = (it.metadata["spine"] as SpineMetadata).timepoint == volume.viewerState.currentTimepoint
if (it.metadata.isNotEmpty()) {
it.visible = (it.metadata["spine"] as SpineMetadata).timepoint == volume.viewerState.currentTimepoint
}
}
}
} else {
hedgehogs.children.forEach { hedgehog ->
val hedgehog = hedgehog as InstancedNode
hedgehogs.children.forEach { hh ->
val hedgehog = hh as InstancedNode
hedgehog.instances.forEach { it.visible = true }
}
}
Expand All @@ -265,10 +268,10 @@ class EyeTrackingDemo: Command{
}

fun addHedgehog() {
log.info("added hedgehog")
val hedgehog = Cylinder(0.005f, 1.0f, 16)
hedgehog.visible = false
// hedgehog.material = ShaderMaterial.fromClass(BionicTracking::class.java,
// listOf(ShaderType.VertexShader, ShaderType.FragmentShader))
hedgehog.setMaterial(ShaderMaterial.fromClass(ParticleDemo::class.java))
var hedgehogInstanced = InstancedNode(hedgehog)
hedgehogInstanced.instancedProperties["ModelMatrix"] = { hedgehog.spatial().world}
hedgehogInstanced.instancedProperties["Metadata"] = { Vector4f(0.0f, 0.0f, 0.0f, 0.0f) }
Expand Down Expand Up @@ -364,11 +367,10 @@ class EyeTrackingDemo: Command{

},
confirmAction = {
hedgehogs.children.removeAt(hedgehogs.children.size-1)
hedgehogs.children.removeLast()
volume.children.last { it.name.startsWith("Track-") }?.let { lastTrack ->
volume.removeChild(lastTrack)
}

val hedgehogId = hedgehogIds.get()
val hedgehogFile = sessionDirectory.resolve("Hedgehog_${hedgehogId}_${SystemHelpers.formatDateTime()}.csv").toFile()
val hedgehogFileWriter = BufferedWriter(FileWriter(hedgehogFile, true))
Expand Down Expand Up @@ -456,10 +458,12 @@ class EyeTrackingDemo: Command{

val toggleTracking = ClickBehaviour { _, _ ->
if (tracking) {
log.info("deactivating tracking...")
referenceTarget.ifMaterial { diffuse = Vector3f(0.5f, 0.5f, 0.5f) }
cam.showMessage("Tracking deactivated.",distance = 1.2f, size = 0.2f)
dumpHedgehog()
} else {
log.info("activating tracking...")
addHedgehog()
referenceTarget.ifMaterial { diffuse = Vector3f(1.0f, 0.0f, 0.0f) }
cam.showMessage("Tracking active.",distance = 1.2f, size = 0.2f)
Expand Down Expand Up @@ -573,7 +577,8 @@ class EyeTrackingDemo: Command{
* If [hedgehog] is not null, the cell track will not be added to the scene.
*/
fun dumpHedgehog() {
var lastHedgehog = hedgehogs.children.last() as InstancedNode
log.info("dumping hedgehog...")
val lastHedgehog = hedgehogs.children.last() as InstancedNode
val hedgehogId = hedgehogIds.incrementAndGet()

val hedgehogFile = sessionDirectory.resolve("Hedgehog_${hedgehogId}_${SystemHelpers.formatDateTime()}.csv").toFile()
Expand Down Expand Up @@ -617,21 +622,11 @@ class EyeTrackingDemo: Command{

// logger.info("---\nTrack: ${track.points.joinToString("\n")}\n---")

val master = if(lastHedgehog == null) {
val m = Cylinder(3f, 1.0f, 10)
m.ifMaterial {
ShaderMaterial.fromFiles("DefaultDeferredInstanced.vert", "DefaultDeferred.frag")
diffuse = Random.random3DVectorFromRange(0.2f, 0.8f)
roughness = 1.0f
metallic = 0.0f
cullingMode = Material.CullingMode.None
}
m.name = "Track-$hedgehogId"
val mInstanced = InstancedNode(m)
mInstanced
} else {
null
}
val m = Cylinder(3f, 1.0f, 10)
m.setMaterial(ShaderMaterial.fromClass(ParticleDemo::class.java))

m.name = "Track-$hedgehogId"
val master = InstancedNode(m)

val parentId = 0
val volumeDimensions = volume.getDimensions()
Expand All @@ -651,7 +646,7 @@ class EyeTrackingDemo: Command{
trackFileWriter.write("$tp\t${p.x()}\t${p.y()}\t${p.z()}\t${hedgehogId}\t$parentId\t0\t0\n")
}

master?.let { volume.addChild(it) }
master.let { volume.addChild(it) }

trackFileWriter.close()
}
Expand Down
31 changes: 17 additions & 14 deletions src/main/kotlin/sc/iview/commands/demo/advanced/HedgehogAnalysis.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import graphics.scenery.utils.extensions.*
import graphics.scenery.utils.lazyLogger
import org.slf4j.LoggerFactory
import java.io.File
import kotlin.math.log
import kotlin.math.sqrt

/**
Expand Down Expand Up @@ -54,19 +55,20 @@ class HedgehogAnalysis(val spines: List<SpineMetadata>, val localToWorld: Matrix
* From a [list] of Floats, return both the index of local maxima, and their value,
* packaged nicely as a Pair<Int, Float>
*/
private fun localMaxima(list: List<Float>): List<Pair<Int, Float>> =
list.windowed(3, 1).mapIndexed { index, l ->
val left = l[0]
val center = l[1]
val right = l[2]

// we have a match at center
if(left - center < 0 && center - right > 0) {
index + 1 to center
} else {
null
}
}.filterNotNull()
private fun localMaxima(list: List<Float>): List<Pair<Int, Float>> {
return list.windowed(6, 2).mapIndexed { index, l ->
val left = l[0]
val center = l[2]
val right = l[4]

// we have a match at center
if (left < center && center > right) {
index * 2 + 2 to center
} else {
null
}
}.filterNotNull()
}

data class SpineGraphVertex(val timepoint: Int,
val position: Vector3f,
Expand Down Expand Up @@ -175,7 +177,8 @@ class HedgehogAnalysis(val spines: List<SpineMetadata>, val localToWorld: Matrix
// step3: connect localMaximal points between 2 candidate spines according to the shortest path principle
// get the initial vertex, this one is assumed to always be in front, and have a local maximum - aka, what
// the user looks at first is assumed to be the actual cell they want to track
val initial = candidates.first().filter { it.value>startingThreshold }.first()
logger.info("candidates are: ${candidates.joinToString { ", " }}")
val initial = candidates.first().first { it.value > startingThreshold }
var current = initial
var shortestPath = candidates.drop(1).mapIndexedNotNull { time, vs ->
// calculate world-space distances between current point, and all candidate
Expand Down
26 changes: 15 additions & 11 deletions src/test/kotlin/sc/iview/StartEyeTrackingDirectly.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import graphics.scenery.utils.extensions.times
import graphics.scenery.utils.lazyLogger
import graphics.scenery.volumes.RAIVolume
import graphics.scenery.volumes.TransferFunction
import org.joml.Vector3f
import org.scijava.command.CommandService
import org.scijava.ui.UIService
import sc.iview.SciView
Expand All @@ -17,17 +19,19 @@ fun main() {
val uiService = context?.service(UIService::class.java)
uiService?.showUI()

sv.open("C:/Software/datasets/MastodonTutorialDataset1/datasethdf5.xml")
val volumes = sv.findNodes { it.javaClass == RAIVolume::class.java }
volumes.first().let {
it as RAIVolume
it.minDisplayRange = 400f
it.maxDisplayRange = 1500f
val tf = TransferFunction()
tf.addControlPoint(0f, 0f)
tf.addControlPoint(1f, 1f)
it.transferFunction = tf
}
sv.open("C:/Software/datasets/MastodonTutorialDataset1/datasethdf5.xml")
val volumes = sv.findNodes { it.javaClass == RAIVolume::class.java }
volumes.first().let {
it as RAIVolume
it.minDisplayRange = 400f
it.maxDisplayRange = 1500f
val tf = TransferFunction()
tf.addControlPoint(0f, 0f)
tf.addControlPoint(1f, 1f)
it.transferFunction = tf
it.spatial().scale *= 20f
it.spatial().scale.z *= -1f
}

val command = sv.scijavaContext!!.getService(CommandService::class.java)
val argmap = HashMap<String, Any>()
Expand Down

0 comments on commit 4b4bd77

Please sign in to comment.