Comments (21)
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.
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.
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.
Hi
Quick update on this. Once I get these pull requests done it should be possible to concisely write a spot detector using ops.
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.
@bnorthan That is beautiful!
from imagej-ops.
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'.
- 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.
- 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".
- 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.
- 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.
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.
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.
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.
@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.
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.
@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.
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.
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.
@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.
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.
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.
@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.
from imagej-ops.
Thanks @hinerm. The tests work now. I pushed a new branch (very simple, I just added the one script).
Let me know if anyone has any comments on the script. If it looks OK I can merge it. Thanks
from imagej-ops.
Looks fantastic to me @bnorthan 👍
from imagej-ops.
Related Issues (20)
- Median not returning mean of two middle values for even number of values HOT 8
- Add stats.mode op to compute modal value
- Confusing behavior for histogram HOT 2
- Quesrtion: Sobel filter HOT 3
- SobelRAI derivativeComputer array error prone if dimension mismatch HOT 5
- AbstractPadAndFFTFilter overrides OutOfBoundsFactory parameter of PadAndConvolveFFTF HOT 7
- Ops filter gauss does not respect the image dimensions HOT 1
- JOML version from parent pom conflicts with current scenery/sciview
- Repeated computation of co-occurrence matrix in haralick features
- Yen threshold differs from IJ1 HOT 4
- Fractal Dimension creates thousands of zombie threads that crash ImageJ HOT 4
- filter/addPoissonNoise hangs up with large pixel values
- Size inconsistencies for Polygon2Ds HOT 2
- Improve OpSearchResult to give limited type information in stringified op HOT 2
- OpListings ignore preallocated outputs
- DefaultGaussRAI.compute() reports cryptic IAE for sigma dimension mismatch HOT 1
- ClassCastException from ConstantToIIOutputII
- OpSearcher reduces OpListings too eagerly HOT 3
- CreateOutputFFTMethods requires a image creator that can take an ImgFactory HOT 1
- FrangiVesselness: Auto-fill the spacing field
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from imagej-ops.