Coder Social home page Coder Social logo

Comments (21)

bnorthan avatar bnorthan commented on August 22, 2024

Hi Curtis

Eventually it would be nice to have something as below. Still need Rolling-ball and a better convolver design. By the way, are you planning to put the ops in namespaces eventually?? (like ops.threshold.otsu(...) ).

(Farther down below is where I am at as of today, not as pretty but it works.)

# @OpService ops
# @Dataset input
# @OUTPUT ImgPlus thresholded

# convert to float
converted=ops.convert.toFloat(input)

# background subtraction
backgroundsubtracted=ops.backgroundsubtraction.rollingball(converted, 50)

# Laplacian of Gaussian
log=ops.filter.log(backgroundsubtracted, 3.0)

# threshold
thresholded=ops.threshold.otsu(log)

And here is what it looks like today

# @DatasetService data
# @DisplayService display
# @IOService io
# @OpService ops
# @net.imagej.Dataset inputData
# @OUTPUT net.imglib2.meta.ImgPlus thresholded

from net.imglib2.meta import ImgPlus
from net.imglib2.type.numeric.real import FloatType
from net.imglib2.img.display.imagej import ImageJFunctions

from ij import ImagePlus
from ij.plugin.filter import BackgroundSubtracter

from jarray import array

from fiji.plugin.trackmate.detection import DetectionUtils

from net.imagej.ops.convert import ConvertPixCopy

###############################################################
# Step 1:  Rolling ball background subtraction (still uses IJ1)
###############################################################

# wrap as ImagePlus
imp=ImageJFunctions.wrap(inputData, "wrapped")

# create and call background subtractor
bgs=BackgroundSubtracter()
bgs.rollingBallBackground(imp.getProcessor(), 50.0, False, False, True, True, True) 

# wrap the result of background subtraction as Img
iplus=ImagePlus("bgs", imp.getProcessor())
imgBgs=ImageJFunctions.wrapShort(iplus)


###############################################################
# Step 2:  Laplacian of Gaussian Filtering
###############################################################

# convert to 32 bit
imgBgs32=ops.run("createimg", imgBgs, FloatType())
ops.convert(imgBgs32, imgBgs, ConvertPixCopy() )

# create the Laplacian of Gaussian filter
kernel = DetectionUtils.createLoGKernel( 3.0, 2, array([1.0, 1.0], 'd' ) )

# create the output Img for convolution
log=ImgPlus( ops.run("createimg", inputData.getImgPlus(), FloatType() ) )

# apply the log filter
ops.convolve(log, imgBgs32, kernel)


###############################################################
# Step 3:  Threshold
###############################################################

# apply the threshold operation
thresholded = ops.run("triangle", log)
display.createDisplay("thresholded", data.create(ImgPlus(thresholded)))

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

Thanks for the update, @bnorthan. I think there are some great targets for the framework embedded in your "ideal" and "current" scripts above. It would be good to make an explicit list of those and file them as issues, so we can make concrete progress toward it.

Regarding namespaces: I actually thought about that during the last hackathon, but tentatively was against it (in my own head) since it would potentially complicate things. They can certainly be simulated using names like threshold_otsu, threshold_triangle, etc. If you really want the dot though, it makes things more complicated, because while you could write threshold.otsu for the op name, you cannot embed a dot into a Java method name. So writing ops.threshold.otsu wouldn't work. I guess I could tackle that as part of issue #19, though.

I do think namespaces are a perfect fit for things like the threshold methods. @dietzc? @dscho? @hinerm? Any opinion?

from imagej-ops.

dietzc avatar dietzc commented on August 22, 2024

just my 2 cents: I think addressing namespaces as part of #19 makes sense. But this is rather a nice to have (priority = low). Anyway, targeting the scripts mentioned by @bnorthan makes completely sense.

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

Hi

Quick update on this. Once I get these pull requests done it should be possible to concisely write a spot detector using ops.

#94
#76
#48

This code also uses IJ1 to generate a result table so it also demonstrates interoperability.

# @DatasetService data
# @DisplayService display
# @OpService ops
# @net.imagej.Dataset inputData

from net.imglib2.meta import ImgPlus
from net.imglib2.img.display.imagej import ImageJFunctions

from jarray import array
from ij import IJ

# create a log kernel
logKernel=ops.logKernel(2, 1.0);

# convolve with log kernel
logFiltered=ops.convolve(inputData, logKernel);

# display log filter result
display.createDisplay("log", ImgPlus(logFiltered));

# otsu threshold and display
thresholded = ops.run("threshold.otsu", logFiltered)
display.createDisplay("thresholded", ImgPlus(thresholded));

# convert to imagej1 imageplus so we can run analyze particles
impThresholded=ImageJFunctions.wrap(thresholded, "wrapped")

# convert to mask and analyze particles
IJ.run(impThresholded, "Convert to Mask", "")
IJ.run(impThresholded, "Analyze Particles...", "display add");
IJ.run("Close"); '''

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

@bnorthan That is beautiful!

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

@ctrueden, @dscho, @dietzc

Looks like you guys are getting lots done. Thanks for merging those pull requests. I tested this script this morning using the new 'master' and using the hela cells-image from 'sample images'.

  1. It seems to be working for 2D images. A good test image is the red channel of hela-cells. That image has lots of spots.
  2. For nd images. one small change is needed logKernel=ops.logKernel(2, 1.0) --> logKernel=ops.logKernel(inputData.numDimensions(), 1.0); Though even with this change the script fails on the "Convert to mask" step with the message "This command does not work with virtual stacks".
  3. I think 'inputData' ends up being the most recently opened image instead of the active image. Things got a bit confusing with multiple images open. If I recall correctly this issue is known and being worked on.
  4. For nd images I still need to read and handle the axis meta data. For example for x, y and channels we would need to "create a 2D filter and apply to each channel", for x,y,z we would need to "create a 3D filter and apply"... I am guessing this is something to revisit once ImgPlus is finalized.

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

I'll to try polish off the loose ends needed to make this script really work out of the box. In particular, we need Dataset ↔️ ImagePlus converters in SciJava so that the "Enable ImageJ2 data structures" option can go away.

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

Today, @hinerm looked a bit at the imagej-legacy improvements that will be needed to improve this. But I just wanted to comment quickly that I was not able to get the script fully working while at the hackathon (even with "Enable ImageJ2 data structures" enabled). And I haven't had time to play with it again since then. Will try again as time allows...

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

I made a couple of small changes to make it run with the latest imagej release. Though the result may not make sense for ND images. Is there a repository we can put these kind of example scripts in??

# @DatasetService data
# @DisplayService display
# @OpService ops
# @net.imagej.Dataset inputData

from net.imglib2.meta import ImgPlus
from net.imglib2.img.display.imagej import ImageJFunctions

from jarray import array
from ij import IJ

# create a log kernel
logKernel=ops.logKernel(inputData.numDimensions(), 1.0);

# convolve with log kernel
logFiltered=ops.convolve(inputData, logKernel);

# display log filter result
display.createDisplay("log", ImgPlus(logFiltered));

# otsu threshold and display
thresholded = ops.run("threshold.otsu",logFiltered)
display.createDisplay("thresholded", ImgPlus(thresholded));

# convert to imagej1 imageplus so we can run analyze particles
impThresholded=ImageJFunctions.wrap(thresholded, "wrapped")

# convert to mask and analyze particles
IJ.run(impThresholded, "Convert to Mask", "")
IJ.run(impThresholded, "Analyze Particles...", "display add");
IJ.run("Close");```

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

@bnorthan Absolutely - all the SciJava scripting components have example scripts in a src/main/resources/script-templates/${LANGUAGE} directory, (e.g. beanshell).

Any component can follow this same pattern and I believe the scripts will be automatically detected as examples in the script editor.

Since your script uses ImageJ classes and is demonstrating ops use I think it makes sense to keep it in the imagej-ops component, e.g. in a new src/main/resources/script-templates/Ops directory?

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

Hi @hinerm

Since my script is Jython I assume I should add it to the scripting-jython repo in the below directory?? Is that correct? Thanks for letting me know.

https://github.com/scijava/scripting-jython/tree/master/src/main/resources/script-templates/

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

@bnorthan Script templates can go in any component's src/main/resources/script-templates directory, but they should go in a component that makes sense for their dependencies.
Since your script uses ij.IJ, it actually makes the most sense to put it in imagej-legacy since that's our IJ 1.x/IJ2 bridge component.

We're about to do a pass through our scripting repos to rename script-templates to script_templates as the former interferes with javadoc generation... so let's just put your script in imagej-legacy/src/main/resources/script_templates/

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

just kidding.. we want to put it here:

https://github.com/imagej/imagej-legacy/tree/master/src/main/resources/script_templates/Python

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

Hi Mark

I'm having trouble building/testing imagej-legacy with maven. The LegacyOpenerTest is failing in "TestPaulsMacro" on 'assertEquals(3, (int) nResults)'. Any ideas why?? Anything I could do differently to fix it?? Thanks --

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

@bnorthan because it is the worst unit test ever. It shares options with your Fiji installation, and requires ImageJ2 to be disabled. So open up Fiji and run Edit>Options>ImageJ2 and disable everything. Then run the test. Awesome!

from imagej-ops.

dscho avatar dscho commented on August 22, 2024

I agree that it is the worst unit test ever – I wrote it. But then, it tests something very crucial: that the macro you run works no matter what your defaults are. And what it showed is that there is a problem in that ImageJ2 modifies the results of that one test depending on global settings. That is just an undesirable situation for users because it means that their macros might fail depending on something outside their control, or even worse: not fail, but instead yield irreproducible results.

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

Certainly one of the best things I could do would be to fix the bug in SCIFIO (I assume) causing the value discrepancy. But we should probably also temporarily set and then re-set the Imagej2 options values to ensure a consistent test (and even test once with and without IJ2 enabled)

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

@hinerm Agreed on all counts. Furthermore, we should add a global setting (maybe via system property) to disable IJ options persistence completely, for the purposes of unit tests. I.e.: all unit tests should be testing with the default options, unless they explicitly want to do otherwise.

from imagej-ops.

ctrueden avatar ctrueden commented on August 22, 2024

scijava/scijava-common#150

from imagej-ops.

bnorthan avatar bnorthan commented on August 22, 2024

Thanks @hinerm. The tests work now. I pushed a new branch (very simple, I just added the one script).

https://github.com/imagej/imagej-legacy/blob/ops_ij1_example/src/main/resources/script_templates/Python/OpsThresholdIJ1Analyze.py

Let me know if anyone has any comments on the script. If it looks OK I can merge it. Thanks

from imagej-ops.

hinerm avatar hinerm commented on August 22, 2024

Looks fantastic to me @bnorthan 👍

from imagej-ops.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.