Skip to content, Skip to search


Jython Scripting

47,390 bytes removed, 03:03, 11 December 2018
Links: Add aditional link
{{ScriptingLearn | languages}}[ Jython] is an implementation of the [ Python programming language] designed to run on the Java platform.
= Quickstart = Introduction ==
* Press {{key|[}} Jython is an implementation of the Python programming language designed to bring up run on the Java platform. <ref>[[Script Editor] Wikipedia entry on Jython].* Select an example Accessed: 2016-08-30</ref> In ImageJ Jython script from the {{bc is one of several [[Scripting#Supported_languages| Templates | [by languagesupported languages]] | Python}} menu.* Press {{key|Ctrl|R}} to run the script!
== The When to use Jython interpreter plugin ==
The interpreter provides a screen All scripting language supported by ImageJ can be used to access the [ ImageJ API]. There are only differences in how the imports are handled and in the syntax of the selected language. Jython has a prompt. Type any jython syntax that differs from most other language as indentations instead of brackets are used to group code on the prompt to interact with ImageJblocks.
Launch it from {{bc | Plugins | Scripting | The following list will help you to decide if Jython Interpreter}}. See [[Scripting Help]] is the right choice to create scripts for all keybindings, and also [[Scripting comparisons]].ImageJ:
{{Warning * If you have experience with Python you can easily use Jython for ImageJ scripting. But you have to keep in mind that tools commonly used in many Python projects (e.g. Numpy) are not available in Jython. By building your [[Jython_Scripting#Self_written_Jython_modules_for_ImageJ| Note own modules]] you can create complex scripts that otherwise are only possible by writing ImageJ also ships a unified Script Interpreter plugin, accessible from {{bc | Plugins | Scripting | Script Interpreter}}plugins in Java. But it is currently beta quality* If don't have any experience in programming, and the Python language does not work properly due is a good choice to bugsstart with. Once this issue If your only aim is fixedto write scripts for ImageJ, there are other languages you should try first (e.g. [[Groovy_Scripting|Groovy]]).* In Python many problems can be solved with less code than in other languages. Still the unified Script Interpreter will replace code is easy to read. Have a look at the language-specific interpreters such as the Jython Interpreterexamples on this page and decide if you want to start using Python for ImageJ scripting.}}
Within the interpreter, all ImageJ, java.lang.* and TrakEM2 classes are automatically imported. So creating new images and manipulating them is very straighforward.=== Explanation ===
The Java implementation of Python is limited in functionality. One can use the [ standard library], but it's not possible to install additional Python modules. Moreover a growing number of projects build on Python3 which is not fully compatible with Python2 Jython is based on. If you want to start learning Python it's recommended to learn Python3.x instead of Python2.
=== Language basics ===Even with the given limitations Jython is a powerful language for ImageJ scripting. Hopefully the examples on this page can convince you of that.
* Any text after a # is commented out.* There are no line terminators (such as ';' in other languages), neither curly braces to define code blocks.* Indentation defines code blocks.* Functions are defined with <i>def</i>, and classes with <i>class</i>.* Functions are objects, and thus storable in variables.* == Jython (and python in general) accepts a mixture of procedural and object-oriented code.* Jython currently implements the Python language at its 2.5 version. All [ documentation basics for python 2.5] applies to Jython bundled with Fiji (with the remarks listed later).ImageJ ==
==== Importing classes ===={{Notice|For an introduction in ImageJ scripting visit the page [[Scripting_basics|Scripting basics]].}}
{{ImportingClasses | lang = Jython}}You can specify imports in Jython as follows:<source lang="python">from import File</source>Where <code></code> is the class to be imported. See also section [[#Importing_other_.py_scripts_.28modules.29|Importing other ''.py'' scripts (modules)]] for importing user python modules. === Workflow for creating Jython scripts Introduction ===
To create a script for The aim of this page is not to teach how to program in Python. This purpose is much better fulfilled by the GUI, the recommended setup [ documentation of Python2]. The focus of this page is to show how features of the following:Python language can be useful for ImageJ scripting.
* Edit and save a file in your favorite text editorThat is why more complex examples are used that are fully functional. If you want ImageJ1 Just copy the code to insert it into the Menu structure, the file must be saved somewhere under ImageJ plugins folder, have an underscore on the name, and a .py extension.* Run {{bc | Plugins [[Using_the_Script_Editor| Scripting | Refresh Jython scripts}} <b>only</b> the very first time after newly creating the file under any folder or subfolder of ImageJ's plugins folder. A menu item will appear with its name, from which it can be run.* Keep editing (Script Editor]] and saving) the file from your editortry them by yourself. Just select the menu item Extensive in-line documentation is used to execute it over and over. Or use explain the {{bc | Plugins | Utilities | Find Commands...}} window to launch it easily (keybinding 'l')implementation.
The next time Fiji is run, it will setup all your scripts in === Image selection using the Plugins menu.GenericDialog class ===
If all you need This example script will create up to 10 new images and create a GenericDialog to select 3 of them. Finally the names of the selected images are printed to the Log window. It is a script recommended to copy the code to the [[Using_the_Script_Editor|Script Editor]] and run in headless mode, simply do:it by yourself.
fiji The following list links to documentation of the used Python features:* [ Future statement definitions]* [ Built-in Functions]* [ str.join()-method]* [ List Comprehensions]* [ Generator Expressions]* [ filepathdo-for-python-parameters ** (double star) and * (star) parameters]* [ Top-level script environment (__main__)]* [ Purpose of the single underscore “_” variable]
=== Some limitations of jython ===
{{Box GitHubEmbed| floatorg=right imagej| titlerepo=What about NumPy and SciPy?imagej-scripting| If you like Python, you probably want to use Python modules such as the excellent [ NumPy] and [http://www.scipy.orgpath=src/ SciPy] libraries. Unfortunately, Jython does not support linking to Python modules backed by native code. See [http:main/resources/ this thread on the ImageJ forum] for some options and alternativesWiki_Jython_Tutorial_1. This area is somewhere a dedicated programmer could make a huge splash and benefit the entire scientific}}Though jython tries to be as close as possible as python, there are some differences you may experience during scripting.
* <u>Float "special numbers" such as ''NaN'' and ''Inf'' are not handled.</u>For instance, <source lang="python"> a = float('nan') </source>will create the correct float number in python, but will throw an exception in jython.= Using Scripting Parameters ===
Instead, to create a NaN in jython, use:<source lang="python">>>> a = DoubleThe second example is inspired by atomic resolution images recorded with an Transmission Electron Microscope (TEM).NaN>>> print aNaN </source>To test if Such images show a number is NaN:<source lang="python">>>> if Double.isNaNregular structure (acrystal): print ", but the images are noisy because of the low signal. By using a is NaN!"a is NaN! </source>Fourier filter the contrast can be enhanced.
* <u>Some existing python modules The script will create a periodic structure and add some random noise. The user can't be imported in jythoncontrol the parameters of the created image.</u>:: This is for instance realized using [[Script_parameters|Script parameters]]. The Fourier filtering has been created by using the case of the module ''numpy'', which would have been really convenient for analysing data and results[[Introduction_into_Macro_Programming#The_recorder|Recorder]].:::: But see these java numerical libraries: http://math.nistFinally a simple image calculator is used to show that functions can be passed as , of which:
This list links to the documentation of Python features that are introduced with this example:* JaMa (Java Matrix Package):* Java3D (particularly its [ vecmath] package provides general matrix and vector classes ([ GMatrix], [ GVector]).:::: ... are already included in Fiji.
* <u>Your Jython version may be matching a much older Python version than you expect[https://docs.python.<org/u>:: 2/library/functions.html#zip The latest Jython stable release zip(as of May 2015) is 2function]* [http://stackoverflow.7com/questions/8421337/rotating-a-two-dimensional-array-in-python Rotating a two-dimensional array]* [https://docs.0python. Fiji (as of December 2015) distributes Jython org/2.5.3. Any recent Python syntax such as <tt>except ExceptionType as e:</tt> or <tt>with open(filepath, 'r') as f:<reference/tt> will failexpressions.html#lambda Lambda expressions]
== Jython tutorials for ImageJ ==
{{GitHubEmbed|org=imagej|repo=imagej-scripting|path= Defining variables: obtaining the current image ===src/main/resources/script_templates/Tutorials/}}
=== A batch opener using <source lang="python"code>imp = IJos.getImagewalk()</sourcecode>===
Which We have yet introduced some powerful functions build into Python. Another one is <code>walk()</code> from the same as:<source lang="python"code>os</code>imp = WindowManagermodule. It can be used to go through a directory structure and process the contained files.getCurrentImageIn this example <code>walk()</code> is used to batch open images with ImageJ's function <code>openImage()</sourcecode>.
Since calling To read more about the above is long and tediousused features, one can declare a variable that points the following list provides links to the above static methodsadditional information:
<source lang="* [ The walk() function]* [ The documentation of os.path]* [ The listdir() function]* [ Javadoc on IJ.openImage()]* [https://docs.python">.org/2/library/functions.html#isinstance Testing the type of an object using isinstance()]* [ Identifying the type of an object using type()]c = WindowManager* [https://docs.python.getCurrentImageorg/2/reference/simple_stmts.html#continue Using continue to control a loop]<* [https:/source>/ Truth Value Testing]
Above note the lack of parentheses.
To execute the function, just use parentheses on it:{{GitHubEmbed|org=imagej|repo=imagej-scripting|path=src/main/resources/script_templates/Tutorials/}}
<source lang="python"> imp = c()Importing Java module and classes ==</source>Another great feature of Jython is the possibility to use functions from Java jar package that resides in the jar folder of imageJ.
The above gets the value of <i>c</i>, which is the method named getCurrentImage in class WindowManager, === ImageJ and executes it, storing its returned object in <i>imp</i>.Fiji API ===
The following API documentation lists all available module and functions :
* [ ImageJ]
* [ Fiji]
=== Manipulating pixels ===Those package are built-in with Fiji, but any package that resides in the jars folder can be imported provided you know the path to the class.
==== Creating a grayscale ramp image ====First create an image Let's show one example with the ImageJ package and obtain its pixelsthe class [ RoiManager]. According to the javadoc the RoiManager class resides in <code>ij.plugin.frame</code>. Therefore the code will look like :
<source lang="python">
imp from ij.plugin.frame import RoiManagerRM = ImagePlus("my new image", FloatProcessorRoiManager(512, 512)) # we create an instance of the RoiManager classpix rm = impRM.getProcessor().getPixelsgetRoiManager() # "activate" the RoiManager otherwise it can behave strangely
The length === Using openCV in Jython ===It is even possible to use most of an arrayopencv functionalities within Jython/Fiji. There are several options (see the [ wiki page about opencv]), yet the most straight forward is probably IJ-OpenCV which is available via the update sites. It will automatically download the necessary packages and dependencies in your Fiji installation.
<source lang="python">n_pixels = len(pix)<A manual installation is also possible by putting the jar packages in the jar folder of imageJ. They are avalaible on the [https:/source> Then loop to modify them: <source lang="python"># catch widthw = imp/github.getWidth() # create a ramp gradient from left to rightfor i in range(len(pix)): pix[icom/joheras/IJ-OpenCV IJopenCV github] = i % w # adjust min and max, since we know themimpwhich even provides a maven option.getProcessor().setMinAndMax(0, w-1)</source>
==== Matrices ==== The first thing to know about OpenCV is that most functions work with an OpenCV matrix object... and show Fortunately, the new imageIJ-OpenCV project provides some converters :
<source lang="python">
imp#@ ImagePlus ImP from</source>ij import ImagePlusMatConverterfrom ijopencv.opencv import MatImagePlusConverter==== Creating a random 8-bit image ====from ij import ImagePlus
First import necessary packages: Random, from standard java util library, and [http://www# Convert ImagePlus (actually the contained ImageProcessor) to Matrix objectimp2mat = ImagePlusMatConverter()ImMat = imp2mat.jythontoMat( jarray], the Jython module for native java arrays:getProcessor())print ImMat
<source lang# Convert Matrix object to ImageProcessormat2ip = MatImagePlusConverter()NewIP = mat2ip.toImageProcessor(ImMat)NewImp =ImagePlus("pythonMatrix converted back to ImagePlus">from java.util import Random, NewIP)from jarray import zerosprint NewImP
Then create the array and fill it with random bytes:Such kind of converter is also available for PointRoi to opencv keypoints...
<source lang="python">width = 512height = 512Now to use opencv function, we use the [ JavaCPP API] that contains almost all functions of opencv.
pix = zeros(width * height, 'b')
('z' = boolean, 'c' = char, 'b' = byte, 'h' = short, 'i' = int, 'l' = long, 'f' = float and 'd' = double, as explained in the [ jarray documentation].)
Now make a new IndexColorModel (that's what ImageJ's ij.process.LUT class is) for 8-bit images:
<source lang="python">
channel = zeros(256, 'b')
for i in range(256):
channel[i] = (i -128)
cm = LUT(channel, channel, channel)
... and compose a ByteProcessor from the pixels, and assign it to an ImagePlus:
<source lang="python">
imp = ImagePlus("Random", ByteProcessor(width, height, pix, cm))
==== Creating a random image, the easy way ====
All the above can be summarized like the following:
<source lang="python">
from java.util import Random
imp = IJ.createImage("A Random Image", "8-bit", 512, 512, 1)
=== Running a watershed plugin on an image ===
<source lang="python">
# 1 - Obtain an image
blobs = IJ.openImage("")
# Make a copy with the same properties as blobs image:
imp = blobs.createImagePlus()
ip = blobs.getProcessor().duplicate()
imp.setProcessor("blobs copy", ip)
# 2 - Apply a threshold: only zeros and ones
# Set the desired threshold range: keep from 0 to 74
ip.setThreshold(147, 147, ImageProcessor.NO_LUT_UPDATE)
# Call the Thresholder to convert the image to a mask, "Convert to Mask", "")
# 3 - Apply watershed
# Create and run new EDM object, which is an Euclidean Distance Map (EDM)
# and run the watershed on the ImageProcessor:
# 4 - Show the watersheded image:
The EDM plugin that contains the watershed could have been indirectly applied to the currently active image, which is <i>not</i> recommended:
<source lang="python">
imp = IJ.getImage() # the current image
imp.getProcessor().setThreshold(174, 174, ImageProcessor.NO_LUT_UPDATE), "Convert to Mask", ""), "Watershed", "")
If you had called <i>show()</i> on the image at any early stage, just update the screen with:
<source lang="python">
==== ... and counting particles, and measuring their areas ====
Continuing from the <i>imp</i> above, that contains the now watersheded "blobs" sample image:
<source lang="python">
# Create a table to store the resultstable = ResultsTable()# Create a hidden ROI manager, to store a ROI for each blob or cellroim = RoiManager(True)# Create a ParticleAnalyzer, with arguments:# 1. options (could be SHOW_ROI_MASKS, SHOW_OUTLINES, SHOW_MASKS, SHOW_NONE, ADD_TO_MANAGER, and others; combined with bitwise-or)# 2. measurement options (see [ org.html Measurements])# 3bytedeco. a ResultsTable to store the measurements# 4javacpp. The minimum size of a particle to consider for measurement# 5. The maximum size (idem)# 6. The minimum circularity of a particle# 7. The maximum circularitypa = ParticleAnalyzer(ParticleAnalyzer.ADD_TO_MANAGERopencv_core import Mat, Measurements.AREA, table, 0CvMat, Double.POSITIVE_INFINITY, 0.0, 1.0)pa.setHideOutputImage(True) if pa.analyze(imp): print "All ok"else: print "There was a problem in analyzing", blobs # The measured areas are listed in the first column of the results table, as a float array:areas = table.getColumn(0) </source> To print out the area measurement of each:vconcat
>>> for area in areas: print area 76.0 185.0 658.0 434.0 ...## Typical matrices ##
# Identity Matrix of size (3x3) and type 8-bit
Id = Mat().eye(3,3,0).asMat()
print Id
print CvMat(Id) # handy to visualise the matrix
Now, we want to measure the intensity # Matrix of each particleones (3x3) One = Mat(). To do soones(3, we'll retrieve the ROI from the ROIManager3, set them one at a time on the original 0).asMat(non-watershed, non-thresholded) image stored in the variable <i>blobs</i>, and measure:
<source lang="python"># Create a new list to store the mean intensity values Matrix of each blob:zeros (3x3) means Zero = []Mat().zeros(3,3,0).asMat()
for roi in RoiManager.getInstance().getRoisAsArray(): blobs.setRoi(roi)# Custom Matrices stats = blobs.getStatistics(Measurements.MEAN)# 1D-Matrix can be initialize from a list means.append# For 2D (stats.meanor more)</source>we have to concatenate 1D-Matrices
Finally read out the measured mean intensity value of each blobRow1 = Mat([1, along with its area:2,3,4,5]) # 1D matrix Row2 = Mat([6,7,8,9,10])
<source langTwoColumn ="python">Mat() # initialise outputfor areavconcat(Col1, mean in zip(areasCol2, meansTwoColumn):# output stored in TwoColumn print area, meanCvMat(TwoColumn)
6{{Warning | The <code>org.0 191bytedeco.47368421052633 185javacpp.0 179opencv_core.2864864864865 658Mat</code> object is different than the <code>org.0 205opencv.61702127659575 434core.0 217Mat</code> !! They don't have exactly the same attributes and functions.32718894009216 477.0 212.1425576519916 ... === Creating an image In Fiji you should always use the objects from a text file === A data file containing rows with 4 columns:  ... 399 23 30 10.12 400 23 30 12.34 <code>org.bytedeco.javacpp</code>.}}
... where the columns are X, Y, Z and value, for every pixel in the image.
We assume we know the width and height of the image.
From this sort of data, we create an image, read out all lines and parse the numbers:
<source lang="python">width = 512height = 512stack = ImageStack(width, height)Similarly there is some apparent redudancy for the function in the javacpp API.
file = open("ex : Transform exists in 3 different places :* <code>org.opencv.core.Core.transform</homecode>This one takes <code>org.opencv.core.Mat</albert/Desktop/datacode> as input. It is currently challenging to have such object in Fiji.txt", "r")
try: fp = FloatProcessor(width, height) pix = fp* <code>org.getPixels() cz = 0 # Add as the first slice: stackbytedeco.addSlice(str(cz), fp) # Iterate over all lines in the text file: for line in filejavacpp.readlines(): x, y, z, value = lineopencv_core.split(" ")cvTransform</code> x = int(x) y = int(y) z = int(z) value = float(value) # Advance one slice if the Z changed: if z != cz: # Next slice fp = FloatProcessor(width, height) pix = fp.getPixels() stack.addSlice(str(cz), fp) cz += 1 # Assign the value: pix[y * width + x] = value # Prepare and show a new image: imp = ImagePlus("parsed"using <code>CvArr</code> as input, stack) Ensure closing the file handle but even if an error is thrown:finally: file.close()you manage to convert your input as a <code>CvArr</sourcecode>it crashes Fiji. Apparently it is a deprecated version.
* <code>org.bytedeco.javacpp.opencv_core.transform</code>
That's the one to use ! It takes only <code>org.bytedeco.javacpp.opencv_core.Mat</code> as input, which is the most approriate in Fiji/Jython
=== Obtain/View histogram and measurements from an image ===
The easiest way is ==== Scalar ====In addition to grab an image and call an ImageJ command Matrices, opencv allows to show its histogram:use Scalar objectsA scalar is a 4 item element (v0, v1, v2, v3).If v1=v2=v3=0 then the Scalar is real.
<source lang="python">
imp = IJfrom org.openImage(""), "Histogram", "")</source>opencv_core import Scalar
How ImageJ does it, internally, has to do # Real scalar can be initiated with the [http://imageja float parametersNumber = Scalar( ImageStatisics] class:0)Number = Scalar(float(5))print Number
<source lang="python"># Using an integer as parameter has a different meaningstats Empty = imp.getStatisticsScalar(5)# This initiate an empty Scalar object of size 5print stats.histogram</source>  array('i',[0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 1209, 0, 0, 0, 0, 0, 0, 0, 3511, 0, 0, 0, 0, 0, 0, 0, 7731, 0, 0, 0, 0, 0, 0, 0, 10396, 0, 0, 0, 0, 0, 0, 0, 7456, 0, 0, 0, 0, 0, 0, 0, 3829, 0, 0, 0, 0, 0, 0, 0, 1992, 0, 0, 0, 0, 0, 0, 0, 1394, 0, 0, 0, 0, 0, 0, 0, 1158, 0, 0, 0, 0, 0, 0, 0, 1022, 0, 0, 0, 0, 0, 0, 0, 984, 0, 0, 0, 0, 0, 0, 0, 902, 0, 0, 0, 0, 0, 0, 0, 840, 0, 0, 0, 0, 0, 0, 0, 830, 0, 0, 0, 0, 0, 0, 0, 926, 0, 0, 0, 0, 0, 0, 0, 835, 0, 0, 0, 0, 0, 0, 0, 901, 0, 0, 0, 0, 0, 0, 0, 1025, 0, 0, 0, 0, 0, 0, 0, 1180, 0, 0, 0, 0, 0, 0, 0, 1209, 0, 0, 0, 0, 0, 0, 0, 1614, 0, 0, 0, 0, 0, 0, 0, 1609, 0, 0, 0, 0, 0, 0, 0, 2220, 0, 0, 0, 0, 0, 0, 0, 2037, 0, 0, 0, 0, 0, 0, 0, 2373, 0, 0, 0, 0, 0, 0, 0, 1568, 0, 0, 0, 0, 0, 0, 0, 1778, 0, 0, 0, 0, 0, 0, 0, 774, 0, 0, 0, 0, 0, 0, 0, 1364, 0, 0, 0, 0, 0, 0, 0])  The histogram, area and mean are computed by default. Other values like the median need to be specified. To calculate other parameters, specify them by bitwise-or composition (see flags in [ Measurements]):Empty
<source lang="python"># Alternatively one can set the other values of the Scalarstats Complex = imp.getStatisticsScalar(Measurements.MEAN | Measurements.MEDIAN | Measurements.AREA1,2,3,4)print "mean:", stats.mean, "median:", stats.median, "area:", stats.areaComplex
mean: 103.26857775590551 median: 64.0 area: 65024.
==== Operations ====
It is possible to perform some operations between matrices, or between Scalar and matrices.
If we set a ROI to the image, then we are measuring only for the inside of the ROI. Here we set an oval ROI of radius 25 pixels, centered:
<source lang="python">
radius = 25roi = OvalRoi(impfrom org.width/2 - radius, imp.height/2 -radius, radius*2, radius*2)impbytedeco.setRoi(roi)stats = impjavacpp.getStatistics(Measurements.MEAN | Measurements.MEDIAN | Measurements.AREA)print "mean:"opencv_core import Scalar, stats.mean, "median:", stats.medianMat, "area:", stats.area</source>subtract
mean: 104.96356275303644 median: 64.0 area: 1976.A = Mat([1,2,3,4,5])B = Mat([1,2,-3,-4,0])
Number = Scalar(10.0)
## Number - B ( B-Number is also possible)
Expr = subtract(Number,B)
print CvMat(Expr.asMat())
To display the histogram window ourselves, we may use the [ HistogramWindow] class:## A - BOut = Mat() <source lang="python">subtract(A,B,Out)hwin = HistogramWindowprint CvMat(impOut)
... of which we may grab the image (the plot itself) and save it:== Self written Jython modules for ImageJ ==
<source lang="In Jython you can write all commands line by line in a single file and execute it. To create a neat program, [ functions] and [https://docs.python">plotimage = hwin.getImagePlus()IJorg/2/tutorial/ classes] can be used to structure code. To prevent using copy&past for regularly used functions and classes, "[https:/path/ modules] are the way to choose. Modules are files that contain functions and classes to import into other files.tif")</source>
=== Removing bleeding from To load modules, one channel has to another ===save them to a directory where Jython will find them. Two lines of code will reveal these directories to you:
The technique to use is to divide one channel by the other: the channel to denoise divided by the channel that bled through. The relatively high-level way to do it is to split the channels and call the ImageCalculator with a "Divide" argument: <source lang="python"># 1 - Obtain an RGB image stackimp = WindowManager.getCurrentImage()if imp.getType() != ImagePlus.COLOR_RGB: IJ.showMessage("The active image is not RGB!") raise RuntimeException("The active image is not RGB!") if 1 == imp.getNSlices(): IJ.showMessage("Not a stack!") raise RuntimeException("Not a stack!") # 2 - Prepare stacks to split slicesstack = imp.getStack()red_stack = ImageStack(imp.width, imp.height)green_stack = ImageStack(imp.width, imp.height) # 3 - Iterate all slices -- notice slices are 1<=i<=sizefor i in range(1, imp.getNSlices()+1): slice = stack.getProcessor(i) red_stack.addSlice(str(i), slice.toFloat(0, None)) green_stack.addSlice(str(i), slice.toFloat(1, None)) # 4 - Apply "divide" via ImageCalculator to the red_stack, which is a new 32-bit stack# Don't use the parameters "create" or "float" or "32" in the parameters string# of the calc.calculate call--then the result of the operation would be# in a new stack that opens beyond our control. Without them, results are# applied to the red_stackcalc = ImageCalculator()calc.calculate("Divide stack", ImagePlus("red", red_stack), ImagePlus("green", green_stack)) # 5 - Compose a new color stacknew_stack = ImageStack(imp.width, imp.height)for i in range(1, imp.getNSlices()+1): cp = stack.getProcessor(i).duplicate() cp.setPixels(0, red_stack.getProcessor(i)) new_stack.addSlice(stack.getSliceLabel(i), cp) # 6 - Show the new imageImagePlus("Normalized " + imp.title, new_stack).show()</source>  Alternatively and as an example of direct pixel manipulation, we'll iterate all slices of the image stack, divide the red channel by the green channel, and compose a new stack: <source lang="python"># 1 - Obtain an RGB image stackimp = WindowManager.getCurrentImage()if imp.getType() != ImagePlus.COLOR_RGB: IJ.showMessage("The active image is not RGB!") raise RuntimeException("The active image is not RGB!") if 1 == imp.getNSlices(): IJ.showMessage("Not a stack!") raise RuntimeException("Not a stack!") stack = imp.getStack() # 2 - Create a new stack to store the resultnew_stack = ImageStack(imp.width, imp.height) # 3 - Iterate all slices -- notice slices are 1<=i<=sizefor i in range(1, imp.getNSlices()+1): # Get the slice i slice = stack.getProcessor(i) # Get two new FloatProcessor with the green and red channel data in them red = slice.toFloat(0, None) green = slice.toFloat(1, None) pix_red = red.getPixels() pix_green = green.getPixels() # Create a new FloatProcessor for the normalized result new_red = FloatProcessor(imp.width, imp.height) pix_new_red = new_red.getPixels() # Iterate and set all normalized pixels for k in range(len(pix_red)): if 0 != pix_green[k]: pix_new_red[k] = pix_red[k] / pix_green[k] # Create a ColorProcessor that has the normalized red and the same green and blue channels cp = slice.duplicate() cp.setPixels(0, new_red) # at channel 0, the red # Store the normalized slice in the new stack, copying the same slice label new_stack.addSlice(stack.getSliceLabel(i), cp) # 4 - Show the normalized stacknew_imp = ImagePlus("Normalized " + imp.title, new_stack)</source> Notice that this second approach is much slower: accessing every pixel from jython has a high cost. If you would like to do very fast pixel-level manipulations, use java or [[Clojure Scripting|Clojure]]. === Subtract the minimal value to an image === Which is to say, translate the histogram so that the lowest value is at zero. <source lang="python"># Obtain current image and its pixelsimp = IJ.getImage()pix = imp.getProcessor().convertToFloat().getPixels() # find out the minimal pixel valuemin = reduce(Math.min, pix) # create a new pixel array with the minimal value subtractedpix2 = map(lambda x: x - min, pix) ImagePlus("min subtracted", FloatProcessor(imp.width, imp.height, pix2, None)).show()</source> Notice we used:* The <i>reduce</i> function to obtain a single value from a list of values (the pixel array) by applying a function to every pair of consecutive values (in this case, the Math.min).* <i>lambda</i>, which is used to declare an anonymous function that takes one argument.* The <i>map</i> function, which runs a function given as argument to every element of a list (here, every pixel) and returns a new list with all the results. === Extract a specific color channel for a given time frame of a composite image === Suppose you have a 4D multicolor image, and want to obtain a stack of slices corresponding to a specific color channel and time frame. The [ CompositeImage] is a stack whose slices are interpreted as belonging to specific color channels, Z slices and time frames. To find out which slice corresponds to what, use the <i>getStackIndex</i> method of the [ ImagePlus], which translates between color channels, z slices and time frames to the slice index in the underlying [ ImageStack]. <source lang="python">from ij import IJ, ImagePlus, ImageStack def extractChannel(imp, nChannel, nFrame): """ Extract a stack for a specific color channel and time frame """ stack = imp.getImageStack() ch = ImageStack(imp.width, imp.height) for i in range(1, imp.getNSlices() + 1): index = imp.getStackIndex(nChannel, i, nFrame) ch.addSlice(str(i), stack.getProcessor(index)) return ImagePlus("Channel " + str(nChannel), ch) imp = IJ.getImage()extractChannel(imp, 1, 1).show()</source> Notice that color channels, stack slices and time frames are all 1-based. For example, if you have 3 color channels, then these have indices 1, 2, and 3 (not 0, 1 and 2).  === Visualize any number of TIFF stacks in a single composite multi-color image stack === Suppose you have 1000 stacks of <i>Drosophila</i> fly brains, each with different neurons labeled in a single color channel. Suppose that you have registered all these confocal stacks. Were you to overlay them, you would see whether the labeled neurons overlap in 3D space or not. Here is a script to do that. First, it asks for a directory containing any number of TIF image stacks. It assumes all stacks have the same dimensions, and that they are all single channel (i.e. just red, or just green, etc.). Then, it displays a small window with a listing of many colors: red, green, blue, orange, gray, etc. Any of the hundreds of stacks in the directory can be assigned to each color channel. The stacks are accessed in a virtual way, so even 1000 (one thousand) stacks will be managed just fine in small laptop. One could easily add more color channels. But there are already lots. The script uses [[Imglib]] scripting to normalize images and generate the color composite. See this [ imglib scripting tutorial] for in-depth explanations. [[Image:Corti-multi-channel.png]] <source lang="python"># 2010-12-03 Albert Cardona and Arnim Jenett# At HHMI Janelia Farm, Fiji tutorials class## Select a directory with multiple image stacks# all of the same dimensions, and show a channel# chooser window to visualize up to 5 of them# in red, green, blue, orange, and gray.# # The stacks are all virtual, opened via LOCI# with BFVirtualStack. The composition of the# RGB ColorProcessor is done with the # script.imglib library.# # Each color channel is shown normalized.# Currently works only with TIF stacks,# and it will interpret them as single-channel.  from loci.plugins.util import BFVirtualStackfrom loci.formats import ChannelSeparatorfrom import DirectoryChooserimport osfrom javax.swing import JScrollPane, JPanel, JComboBox, JLabel, JFramefrom java.awt import Color, GridLayoutfrom java.awt.event import ActionListenerfrom script.imglib.math import Compute, Max, Multiplyfrom script.imglib.algorithm import Normalizefrom script.imglib.color import Red, Green, Blue, RGBAfrom mpicbg.imglib.image.display.imagej import ImageJFunctions as IJF  # Choose a directory with lots of tif stacksdc = DirectoryChooser("Choose directory with stacks")srcDir = dc.getDirectory() # Open each tif stack as a virtual BFVirtualStackbfvs = []names = []for filename in os.listdir(srcDir): if filename.endswith(".tif"): print "Reading metadata from", filename cs = ChannelSeparator() names.append(filename) cs.setId(srcDir + filename) bfvs.append( BFVirtualStack(srcDir + filename, cs, False, False, False) ) names.sort()names = ["None"] + names  colorToRGB = {'Red' : [255,0,0],'Green' : [0,255,0],'Blue' : [0,0,255],'Orange' : [255,127,0],'Cyan' : [0,255,255],'Yellow' : [255,255,0],'Magenta' : [255,0,255],'Indigo' : [75,0,130],'Violet' : [238,130,238],'Greyscale' : [255,255,255],'Aquamarine' : [127,255,212],'Navy Blue' : [0,0,128],'Sky Blye' : [135,206,235],'Turquoise' : [64,224,208],'Beige' : [245,245,220],'Brown' : [165,42,42],'Chocolate' : [210,105,30],'Dark wood' : [133,94,66],'Light wood' : [133,99,99],'Olive' : [128,128,0],'Green yellow' : [173,255,47],'Sea green' : [32,178,170],'Khaki' : [240,230,140],'Salmon' : [250,128,114],'Pink' : [255,192,203],'Tomato' : [255,99,71],'Scarlet' : [140,23,23],'Purple' : [128,0,128],'Wheat' : [245,222,179],'Silver grey' : [192,192,192]} # Encode color RGB in floats:tmp = {}for c,rgb in colorToRGB.iteritems(): tmp[c] = [v/255.0 for v in rgb]colorToRGB = tmp # Colors in the desired listing order:colors = ['Red', 'Green', 'Blue', 'Orange', 'Indigo', 'Cyan', 'Yellow', 'Magenta', 'Turquoise', 'Tomato', 'Olive', 'Violet', 'Green yellow', 'Khaki', 'Scarlet', 'Beige', 'Chocolate', 'Silver grey', 'Pink', 'Wheat', 'Sea green', 'Greyscale', 'Light wood', 'Sky Blye', 'Brown', 'Salmon', 'Navy Blue', 'Aquamarine', 'Purple', 'Dark wood'] # Initalize table of colors vs stacks to use:table = {}for k,v in zip(colors, [1] + [0 for i in range(len(colors)-1)]): table[k] = v  def asImg(color, section): global bfvs, table index = table[color] if 0 == index: return 0 # is "None" color return IJF.wrap(ImagePlus("", bfvs[index-1].getProcessor(section))) def maybeNormalize(fn): """ Do not normalize if no images are present. """ if 0 == fn: return fn cursors = [] fn.findCursors(cursors) if len(cursors) > 0: return Multiply(Normalize(fn), 255) return fn def blendColors(section): global bfvs, table, colorToRGB red = 0 green = 0 blue = 0 for colorName,index in table.iteritems(): if 0 == index: continue img = IJF.wrap(ImagePlus("", bfvs[index-1].getProcessor(section))) rgb = colorToRGB[colorName] if 0 != rgb[0]: red = Max(red, Multiply(img, rgb[0])) if 0 != rgb[1]: green = Max(green, Multiply(img, rgb[1])) if 0 != rgb[2]: blue = Max(blue, Multiply(img, rgb[2])) return red, green, blue class VS(VirtualStack): def __init__(self): self.last = None def getProcessor(self, i): """ Channel color composition into a single RGB image, as ColorProcessor. 'i' is the section index, 1<=i<=size """ red, green, blue = blendColors(i) # Transform to RGB by normalizing and scaling to 255 red = maybeNormalize(red) green = maybeNormalize(green) blue = maybeNormalize(blue) # Compose rgb = RGBA(red, green, blue).asImage() self.last = IJF.displayAsVirtualStack(rgb).getProcessor() return self.last def getSize(self): return bfvs[0].getSize() def getSliceLabel(self, i): return str(i) def getWidth(self): return self.last.getWidth() def getHeight(self): return self.last.getHeight() def getPixels(self, i): return self.getProcessor(i).getPixels() def setPixels(self, pix, i): pass  # Create a new image stackprint os.path.split(srcDir)ourImp = ImagePlus(os.path.split(srcDir)[1], VS()) # Create a bunch of panels, one for each color channelall = JPanel()layout = GridLayout(len(colors), 2)all.setLayout(layout) # GUI to choose which stacks is shown in which channelclass Listener(ActionListener): def __init__(self, color, choice, imp): self.color = color self.choice = choice self.imp = imp def actionPerformed(self, event): global table table[self.color] = self.choice.getSelectedIndex() self.imp.updateAndRepaintWindow() for color in colors: all.add(JLabel(color)) choice = JComboBox(names) choice.setSelectedIndex(table[color]) choice.addActionListener(Listener(color, choice, ourImp)) all.add(choice) frame = JFrame("Channels")frame.getContentPane().add(JScrollPane(all))frame.pack() frame.setVisible(True)</source> === Sort all points of a PointRoi into a chain by distance to each other === There may be better ways, but here is one. Read the header to understand its limitations. <source lang="python"># Albert Cardona 2010-12-17 for Victoria Butler at HHMI Janelia Farm# Given a PointRoi, order the points in a chain# Assumes that the point furthest from all points# is the start or the end of the chain. from javax.vecmath import Point2f # Obtain the PointRoi of the current imageproi = IJ.getImage().getRoi() # Interrupt if the ROI is not a PointRoi instance:if proi.getClass() != PointRoi: raise Exception("Not a PointRoi!") class Point(Comparable): def __init__(self, x, y): self.p = Point2f(x, y) self.distances = {} self.distAll = None def distance(self, point): return self.p.distance(point.p) def distanceToAll(self): if self.distAll is None: self.distAll = reduce(lambda a, b: a + b, self.distances.values()) return self.distAll def compareTo(self, point): if self.distanceToAll() < point.distanceToAll(): return -1 return 1 def toString(self): return self.p.toString() def closest(self, points): """ Find the closest point that is not contained in the set of given points. """ next = None dist = Float.MAX_VALUE for p,d in self.distances.iteritems(): if d < dist and not p in points: next = p dist = d return next # Convert PointRoi points to Point instancespx = proi.getXCoordinates()py = proi.getYCoordinates()bounds = proi.getBounds()points = []for i in range(proi.getNCoordinates()): points.append(Point(bounds.x + px[i], bounds.y + py[i])) # Precompute all-to-all distancesallToAll = {}for j in range(len(points)): for k in range(j+1, len(points)): distance = points[j].distance(points[k]) points[j].distances[points[k]] = distance points[k].distances[points[j]] = distance # Choose a starting point.# In this case, we use the point most distant from all other pointspoints.sort()first = points[-1]print "First:", first # Grow the chain from the starting pointchain = [first]seen = set() # for fast look-upseen.add(chain[0])while len(chain) < len(points): next = chain[-1].closest(seen) if next is None: break chain.append(next) seen.add(next) print "Chain:", chain</source> === Correct illumination in a stack: apply the illumination of one slice to all others === The Multi-focus 3D Microscope (Sara Abrahamsson and Matz Gustafsson) takes a single image and later, computationally, 9 image planes are extracted. The middle slice usually has the desired illumination levels, while the other 8 slices (4 before and 4 after) do not. Here is a script to apply the illumination of the 5th slice to all other slices. The script takes a directory of images and processed them all, resulting in new images stored as "*-corrected.tif" in the same directory. <source lang="python"># Albert Cardona 2011-06-09 at HHMI Janelia Farm# Takes a stack of 9 slices# and then computes the mean and stdDev of slice number 5# and normalize the intensity of the other 8 slices# to that of slice 5.## Created for Jiji Chen to process image stacks from# the multifocus 3D microscope from Matz Gustafsson# and Sara Abrahamsson  from math import sqrtimport os def computeMean(pixels): return sum(pixels) / float(len(pixels)) def computeStdDev(pixels, mean): s = 0 for i in range(len(pixels)): s += pow(pixels[i] - mean, 2) return sqrt(s / float(len(pixels) -1)) def process9ImagePlanes(imp): # reference slice refSlice = 5 ref = imp.getStack().getProcessor(5) refMean = sum(ref.getPixels()) / float(len(ref.getPixels())) refStdDev = computeStdDev(ref.getPixels(), refMean)  # New stack with the corrected slices stack = ImageStack(ref.width, ref.height)  for i in range(1, 10): # skip the reference slice if 5 == i: stack.addSlice(imp.getStack().getSliceLabel(5), ref.convertToFloat()) continue ip = imp.getStack().getProcessor(i).convertToFloat() mean = computeMean(ip.getPixels()) stdDev = computeStdDev(ip.getPixels(), mean) ip.add(-mean) ip.multiply(1/stdDev) ip.multiply(refStdDev) ip.add(refMean) stack.addSlice(imp.getStack().getSliceLabel(i), ip)  return ImagePlus(imp.title, stack)  def accept(filename): """ Work only with TIFF files. """ return len(filename) - 4 == filename.rfind(".tif") def run(): dc = DirectoryChooser("pick folder with image stacks") folder = dc.getDirectory() if folder is None: return for filename in filter(accept, os.listdir(folder)): imp = IJ.openImage(os.path.join(folder, filename)) if imp is None: print "Failed to open image:", filename continue corrected = process9ImagePlanes(imp), os.path.join(folder, filename[0:-4] + "-corrected.tif")) run() </source>  === Add a mouse listener to the canvas of every open image === <source lang="python">from java.awt.event sys import MouseAdapter def doSomething(imp): """ A function to react to a mouse click on an image canvas. """ IJ.log("clicked on: " + str(imp)) class ML(MouseAdapter): def mousePressed(self, event): canvas = event.getSource() imp = canvas.getImage() doSomething(imp) listener = ML() for imp in map(WindowManager.getImage, WindowManager.getIDList()): win = imp.getWindow() if win is None: continue win.getCanvas().addMouseListener(listener)</source> After running the script, clicking on any image will result inprinting a line to the log window, like:  clicked on: imp[Untitled-1 400x200x1]  === Add a key listener to the canvas of every open image === <source lang="python">from java.awt.event import KeyEvent, KeyAdapter def doSomething(imp, keyEvent): """ A function to react to key being pressed on an image canvas. """ IJ.log("clicked keyCode " + str(keyEvent.getKeyCode()) + " on image " + str(imp)) # Prevent further propagation of the key event: keyEvent.consume() class ListenToKey(KeyAdapter): def keyPressed(this, event): imp = event.getSource().getImage() doSomething(imp, event) listener = ListenToKey() for imp in map(WindowManager.getImage, WindowManager.getIDList()): win = imp.getWindow() if win is None: continue canvas = win.getCanvas() # Remove existing key listeners kls = canvas.getKeyListeners() map(canvas.removeKeyListener, kls) # Add our key listener canvas.addKeyListener(listener) # Optionally re-add existing key listeners # map(canvas.addKeyListener, kls)</source> === Create a virtual stack from the TIF files present in a folder and its subfolders, recursively === <source lang="python"># Walk recursively through an user-selected directory# and add all found filenames that end with ".tif"# to a VirtualStack, which is then shown.## It is assumed that all images are of the same type# and have the same dimensions. import osfrom import DirectoryChooserfrom ij import IJ, ImagePlus, VirtualStack def run(): srcDir = DirectoryChooser("Choose!").getDirectory() if not srcDir: # user canceled dialog return # Assumes all files have the same size vs = None for root, directories, filenames in os.walk(srcDir): for filename in filenames: # Skip non-TIFF files if not filename.endswith(".tif"): continue path = os.path.join(root, filename) # Upon finding the first image, initialize the VirtualStack if vs is None: imp = IJ.openImage(path) vs = VirtualStack(imp.width, imp.height, None, srcDir) # Add a slice, relative to the srcDir vs.addSlice(path[len(srcDir):]) # ImagePlus("Stack from subdirectories", vs).show() run()</source> === Open the slices of a very large multi-image stack file one by one, and save each as a new image file ===<source lang="python"># 2011-10-18 Albert Cardona for Nuno da Costa# Choose a multi-slice image stack file in a virtual way# and save each slice as an individual image file# in a user-chosen directory. import osfrom loci.plugins.util import BFVirtualStackfrom loci.formats import ChannelSeparator def run(): # Choose a file to open od = OpenDialog("Choose multi-image file", None) srcDir = od.getDirectory() if srcDir is None: # User canceled the dialog return path = os.path.join(srcDir, od.getFileName()) # Choose a directory to store each slice as a file targetDir = DirectoryChooser("Choose target directory").getDirectory() if targetDir is None: # User canceled the dialog return # Ready: cs = ChannelSeparator() cs.setId(path) bf = BFVirtualStack(path, cs, False, False, False) for sliceIndex in xrange(1, bf.getSize() +1): print "Processing slice", sliceIndex ip = bf.getProcessor(sliceIndex) sliceFileName = os.path.join(targetDir, str(sliceIndex) + ".tif") FileSaver(ImagePlus(str(sliceIndex), ip)).saveAsTiff(sliceFileName) run()</source>  === Apply a binary mask to every slice in an image stack === Will work with regular stacks and with any kind of complex stack like a composite image or a 4d volume. Keep in mind that all stack types in ImageJ consists of a sequence of 2d images, each editable with an [ ImageProcessor] obtained from the [ ImageStack] that one can get from the [ ImagePlus]. (The [ ImagePlus] being what the opener or the [ WindowManager] provides.) <source lang="python"># Albert Cardona 2012-10-05 for Sara Abrahamsson## Take a stack of images and a mask,# and clear the area outside the mask for every image.## ASSUMES that the mask:# 1. Is 8-bit;# 2. has the area to keep as 255;# 3. has the area to clear as zeros.  from ij import IJfrom ij import WindowManager as WM # If the images are open:volume = WM.getImage("stack.tif")mask = WM.getImage("mask.tif") # Or if the images have to be loaded from files:# volume = IJ.openImage("/Users/sara/images/stack.tif")# mask ="/Users/sara/images/mask.tif") # Obtain the underlying stack of 2d imagesstack = volume.getStack() # Fill every stack slice with zeros for the area outside the maskfor i in xrange(1, stack.getSize() + 1): # ip is the ImageProcessor for one stack slice ip = stack.getProcessor(i) ip.setValue(0) ip.fill(mask) volume.updateAndDraw()</source> Note that it is counterintuitive that the area outside the mask gets filled with zeros. If you want the area inside the mask to get filled with zeros, then add this step before the loop: <source lang="python">mask = mask.duplicate()mask.invert()</source> === Open all series in a LIF file with Bio-Formats === <source lang="python"> # 2014-11-24 Harri Jäälinoja from import ImagePlusReader,ImporterOptions,ImportProcessimport sys filename = sys.argv[1]opts = ImporterOptions()opts.setId(filename)opts.setUngroupFiles(True) # set up import processprocess = ImportProcess(opts)process.execute()nseries = process.getSeriesCount() # reader belonging to the import processreader = process.getReader() # reader external to the import processimpReader = ImagePlusReader(process)for i in range(0, nseries): print "%d/%d %s" % (i+1, nseries, process.getSeriesLabel(i)) # activate series (same as checkbox in GUI) opts.setSeriesOn(i,True)  # point import process reader to this series reader.setSeries(i)  # read and process all images in series imps = impReader.openImagePlus() for imp in imps: wait = Wait(str(i) + imp.getTitle()) imp.close()  # deactivate series (otherwise next iteration will have +1 active series) opts.setSeriesOn(i, False)</source>   === Open and save movies with the FFMPEG I/O plugin === First note that the FFMPEG I/O plugin was a proof-of-concept that is completely '''unmaintained'''. Then open the [[Fiji Updater]], push the "Manage update sites" at the bottom left of the dialog, and install the [ FFMPEG] plugin by {{Person|Schindelin}} by ticking its checkbox, as [[How_to_follow_a_3rd_party_update_site|explained in more detail here]]. See also the Java source code for the {{GitHub|repo=fiji|tag=8164ae68|path=native/FFMPEG_IO/plugin/src/main/java/fiji/ffmpeg/|label=IO}} class from the [ FFMPEG plugin source code site]. <source lang="python">""" Albert Cardona for Marta Zlatic, 2014-01-24. """ from fiji.ffmpeg import IOfrom java.awt import Colorimport os def load(path, first_frame=0, last_frame=-1): """ Load the whole movie by default. """ io = IO() imp = io.readMovie(path, False, first_frame, last_frame) return imp def save(path, imp, frame_rate=30, bit_rate=400000): """ frame_rate in fps (frames per second). bit_rate defines the quality of the movie: higher bit rate results in larger, higher quality movies. The movie format (e.g. AVI, MPG, etc.) is chosen by the path filename extension. """ io = IO() io.writeMovie(imp, path, frame_rate, bit_rate)  def process(imp, convert, roi, time_zero, time_range): """ Crop, convert to another format, and time-stamp. """ stack = imp.getStack() size = stack.getSize() bounds = roi.getBounds() new_stack = ImageStack(bounds.width, bounds.height) for i in xrange(1, size + 1): ip = convert(stack.getProcessor(i)) ip.setRoi(roi) c = ip.crop() c.setColor(Color.white) time = "%.2f" % (time_zero + time_range * (float(i-1) / (size -1))) c.drawString(time, 5, 15) new_stack.addSlice(str(i), c)  return ImagePlus(imp.title, new_stack)  def batch_process(extension, source_dir, output_dir, convert, roi, time_zero, time_range): for filename in os.listdir(source_dir): if filename.endswith(extension): if os.path.exists(target_dir + filename): # Skip if movie exists at destination continue imp = load(source_dir + filename) imp2 = process(imp, convert, roi, time_zero, time_range) imp.flush() save(target_dir + filename, imp2) imp2.flush()  def convert(ip): """ Convert to 8=bit and crop the range to [0, 128] pixel values. """ c = ip.convertToByte(True) c.setMinAndMax(0, 128) return c  source_dir = '/path/to/list_of_AVI_movies/'target_dir = '/path/to/new_list_of_AVI_movies/' roi = Roi(50, 50, 256, 256)time_zero = 30 # start at 30 secondstime_range = 30 # range of (also) 30 seconds # Process all AVI movie files, saving them also as AVI filesbatch_process('.avi', source_dir, target_dir, convert, roi, time_zero, time_range) </source> === Skeletonize an image and analyze the skeleton === <source lang="python">from ij import IJfrom skeleton_analysis import AnalyzeSkeleton_,Graph,Edge,Vertex # open image, blur, make b/w, skeletonizeimp = IJ.openImage("/path/to/image.tif"),"Gaussian Blur...","sigma=5"),"Make Binary",""),"Skeletonize","") # run AnalyzeSkeleton# (see # and = AnalyzeSkeleton_()skel.setup("",imp)skelResult =, False, True, None, True, True) # get the separate skeletonsgraph = skelResult.getGraph()print len(graph)print skelResult.getNumOfTrees() def getGraphLength(graph): length = 0 for g in graph.getEdges(): length = length + g.getLength() return length # find the longest graphgraph = sorted(graph, key=lambda g: getGraphLength(g), reverse=True)longestGraph = graph[0] # find the longest edgeedges = longestGraph.getEdges()edges = sorted(edges, key=lambda edge: edge.getLength(), reverse=True)longestEdge = edges[0] </source> === Find peaks in a 3D image === <source lang="python"># @ImagePlus imp from fiji.plugin.trackmate.detection import DogDetectorfrom ij.gui import PointRoifrom ij.plugin.frame import RoiManagerfrom net.imglib2.img.display.imagej import ImageJFunctions # Set the parameters for DogDetectorimg = ImageJFunctions.wrap(imp)interval = imgcal = imp.getCalibration()calibration = [cal.pixelWidth, cal.pixelHeight, cal.pixelDepth]radius = 0.2 # the radius is half the diameterthreshold = 100doSubpixel = TruedoMedian = False # Setup spot detector# (see # public DogDetector(RandomAccessible<T> img,# Interval interval,# double[] calibration,# double radius,# double threshold,# boolean doSubPixelLocalization,# boolean doMedianFilter)detector = DogDetector(img, interval, calibration, radius, threshold, doSubpixel, doMedian) # Start processing and display the resultsif detector.process(): # Get the list of peaks found peaks = detector.getResult() print str(len(peaks)), "peaks were found."  # Add points to ROI manager rm = RoiManager.getInstance() if not rm: rm = RoiManager()  # Loop through all the peak that were found for peak in peaks: # Print the current coordinates print peak.getDoublePosition(0), peak.getDoublePosition(1), peak.getDoublePosition(2) # Add the current peak to the Roi manager proi = PointRoi(peak.getDoublePosition(0) / cal.pixelWidth, peak.getDoublePosition(1) / cal.pixelHeight) proi.setPosition(int(peak.getDoublePosition(2) / cal.pixelDepth)) rm.addRoi(proi)  # Show all ROIs on the image rm.runCommand(imp, "Show All") else: print "The detector could not process the data."</source> == Tips and Tricks == === Getting a list of all members in one package === You can use the Python function ''dir(<package>)'' to see the contents of a package: <source lang="python">import ijprint dir(ij)
'''Note:''' As of April 26nd, 2010, you need to start Fiji with  fiji -Dpython.cachedir.skip=false -- for ''dir(<package>)'' to work. === Specifying the encoding of the source === When your source code contains non-ASCII characters (such as umlauts), Jython will complain with a ''SyntaxError: Non-ASCII character in file '<iostream>', but no encoding declared''. You can fix running this issue by putting the line  # -*- coding: iso-8859-15 -*- as first line into your source code (or if it starts with ''#!/usr/bin/python'', as second line), as suggested [ here]. You might need to replace the string ''iso-8859-15'' by something like ''utf-8'' if your source code result is encoded in UTF-8. === Changing the default encoding === By default, Jython encodes the standard an output (and other streams) with the ASCII encoding. Often, this is not what you want. You can change the default encoding like this:
<source lang="'python"'>from org['/home/michael/Software/', '/home/michael/Software/ImageJ.pythonapp/jars/jython-shaded-2.7.core import codecscodecs0.setDefaultEncoding(jar/Lib'utf-8, '__classpath__', '__pyclasspath__/')]
=== Error handling with try This tells us that the folder <code>jars/ except Lib/ finally === See complete documentation at: [http:</code> inside our ImageJ/jythonpodcastFiji directory is the right place to save modules.hostjava.netAs <code>Lib/jythonbook</chapter6.html jython book chapter 6]code> does not exist by default, we have to create it.
When a module is imported for the first time, Jython will compile it to Java code. If there is a module named <source lang="python"code>x = 10y =</code>, Jython will create a file called <code>myModule$py.class</code>. The next time the module is imported, Jython will use the class file instead of the py file. When modifying the module, it necessary to restart ImageJ/Fiji to use the modified one. A work around is the following code (found at [ stackoverflow]) that will force Jython to recompile all modules:
try: z <source lang= x / y'python'>except NameError, e1:# Use this to recompile Jython modules to class files. print "A variable is not defined!", e1from sys import modulesexcept ZeroDivisionError, e2: print "Dividing by zero doesn't make any sense! Error:", e2modules.clear()finally# Imports of Jython modules are placed below: print "This line will always print no matter what error occurs."import myModule
Which prints:=== Adding a custom directory ===
Dividing by zero doesnIf you don't make any sense! Errorwant to use <code>jars/Lib/</code> to save your modules, you have to extend the array <code>sys.path</code>: integer division or modulo by zero This line will always print no matter what errors occurs
To catch any kind of errors, use <i>sys.exc_info</i>: <source lang="python">import sys try: z = x / zexcept: print "Error: ", sys.exc_info()</source> Which prints:  Error: (<type 'exceptions.NameError'>, NameError("name 'x' is not defined",), <traceback object at 0x2>)  To ensure that you see the stack trace, print it to the ImageJ log window instead of stdout (whathever the latter may be): <source lang="python"> IJ.log(str(sys.exc_info()))</source> === Importing other ''.py'' scripts (modules) === If you want to import other python files, you need to ''import'' them. This requires that the files are found in the so-called ''search path'', a list of directories in which Jython looks for the modules (''.py'' files) to import. You can easily extend the search path: <source lang="python">
from sys import path
from java.lang.System import getProperty
# extend the search path by $FIJI_ROOT/bin/
# 'fiji.dir' works for plain ImageJ, too.
path.append(getProperty('fiji.dir') + '/bin')
 # Now you an alternative can import $FIJI_ROOT/bin/compat.pyimport compat</source> A situation you are likely to encounter is when you have multiple jython scripts in a folder under be the fiji plugins folder. For example, suppose you have the folder ''my scripts'' under the fiji ''plugins'' folder, in which you have the script '''' with the following filter functions in it: <source lang="python">users home directory# Script plugins/my scripts/Filters.pyfrom ij import IJfrom ij.plugin import Duplicator def median(imp, radius): """ Apply a median filter to a copy of the given ImagePlus, and return it. """ copy = Duplicator().run(imp), "Median...", "radius=" + str(radius)) return copy def removeOutliers(imp, radius, threshold, bright): """ Apply a remove outliers filter to a copy of the given ImagePlus, and return it. """ copy = Duplicator().run(imp) which = "Bright" if bright else "Dark", "Remove Outliers...", "radius=" + str(radius) \ + " threshold=" + str(threshold) + " which=" + which) return copy</source> And now you have a second script in which you want to use a function from the '''' script: <source lang="python">from ij import IJimport sysfrom java.lang.System import getPropertysys.path.append(getProperty("fiji.dir") + "/plugins/my scripts")from Filters import median imp = IJ.getImage()medianFiltered = median(imp, 5.0)</source> === Defining a class and creating instances of the new class === A simple class to store an X,Y coordinate. (In real code, just use javax.vecmath.* classes such as Point3f, Point3d, etc.) The constructor is defined with <i>__init__</i>, and takes at least one argument , named <i>self</i> by convention (you may name it something else, like <i>this</i>). <source lang="python">from math import sqrt, pow class Point: def __init__(self, x, y): self.x = x self.y = y def distance(self, other): return sqrt(pow(self.x - other.x, 2), pow(self.y - other.y, 2))</source> ... and create two instances, and measure the distance between them. To create the new instances, we use the name of the class with the arguments in brackets: <source lang="python">p1 = Point(10, 20)p2 = Point(40, 55.3) print "Distance:", p1.distance(p2)</source> === Adding a static method to a class === A static method is a method of a class that doesn't need a <i>self</i> first argumentuser. You may call this method by using the name of the class alone--you donhome't need to invoke it on an instance. To declare a method as static, decorate it with <i>@staticmethod</i>, as shown below for method <i>two</i>: <source lang="python">class Numbers:  def one(self): return 1  @staticmethod def two(): return 2</source> Now, to invoke these methods, notice how <i>two</i> doesn't need to be invoked on an instance (we merely prepend the class name), but <i>one</i> does: <source lang="python">print Numbers.two() that = Numbers()print</source> Why would you want to use a static method? It is useful to keep the namespace tidy, to avoid name collisions. === Creating multi-dimensional native java arrays === Suppose you want to create a one-dimensional double array, the equivalent of '''double[]''' in java. This is what you would do: <source lang="python">from jarray import array data = [1.0, 2.0, 3.0, 4.0] arr = array(data, + 'd')</source> Other accepted primitive array types are: z boolean c char b byte h short i int l long f float d double But now suppose you want a two-dimensional double array, the equivalent of '''double[][]''' in java. How to do that? Here's how: <source lang="python">from jarray import array data = [[1.0, 2.0], [3.0, 4.0]]twoDimArr = array(data, Class.forName('[D'))</source> Essentially, what we did is to give the function '''array''' the argument '''class of a one-dimensional double array''', so that it will create an array of that--hence a two-dimensional double array. For a three-dimensional array in jython, you'd just add another '''[''' (square bracket) to the class name: <source lang="python">from jarray import array data = [[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]]threeDimArr = array(data, Class.forName('[[D'))</source> See the [ jarray documentation]. To create primitive arrays of any class, pass along the class itself. For example, a native array of '''String''': <source lang="python">from jarray import array texts = ["one", "two", "three"] strings = array(texts, String)</source> Of course arrays can also be created empty. For numbers, all values will be zero. For an arbitrary class such as '''String''', all values will be null (or None, in python parlance). In the example below, we create an empty two-dimensional array of '''double[N][]''' type, where the smaller, inner arrays are null (just like in java a '''new double[5][]''' would have the second-order also all null): <source lang="python">from jarray import zeros twoDimArr = zeros(5, Class.forName("[D")) print twoDimArr# prints: array([D, [None, None, None, None, None]) # fill each slot with a new array of length 3:for i in range(len(twoDimArr)): twoDimArr[i] = zeros(3, 'd') print twoDimArr#prints: array([D, [array('d', [0.0, 0.0, 0.0]), array('d', [0.0, 0.0, 0.0]),# array('d', [0.0, 0.0, 0.0]), array('dJythonModules', [0.0, 0.0, 0.0]), array('d', [0.0, 0.0, 0.0])])</source>  === Inline java code inside jython: the Weaver === Jython is great at doing high-level operations on images. But sometimes one wants to edit pixels specifically. Such low-level loops in jython are far from the performance offered by java. But writing a special-purpose java class for a minor piece of code is painful and requires specific java skills regarding code compilation and classpath management. The weaver removes all the pain. Here is an example, where the <i>float[]</i> pixels array of the current image is iterated to compute the mean intensity: <source lang="python">from fiji.scripting import Weaverfrom ij import IJfrom java.lang import Double # The currently open imageimp = IJ.getImage() fp = imp.getProcessor().convertToFloat()pixels = fp.getPixels() # a float array, float[]w = Weaver.inline( """ double sum = 0; for (int i=0; i<pixels.length; i++) { sum += pixels[i]; } return sum / pixels.length; """, {"pixels" : pixels}, Double) mean = print mean</source> The above is trivial and it is meant only as an example (there are better ways to get the mean value, such as via <i>imp.getStatistics()</i>. Notice that the <i>Weaver.inline</i> function takes three arguments: the java code to inline, the map of bindings, and the return type. In the example, we pass only the <i>float[]</i> pixels array, and define <i>Double</i> as the return type. The return type is optional. Internally, bindings are represented as fields in a java class, set as either primitives (like double, int ...) or the least general public class or superclass of the object to bind. There is a fourth optional argument for <i>inline</i> (boolean) to show the generated java code in a tab of the Script Editor. A better example that exploits the capabilities of the Weaver is the following: compile the function once, and then call it over and over with different parameters. The bindings cannot be changed, but if they are arrays or collections, one can change the elements of these collections. For example, to obtain a new ImageStack that is the result of applying XOR to each consecutive pair of slices (which will give you the boundaries of objects): <source lang="python">from fiji.scripting import Weaver # The currently open image, an 8-bit stackimp = IJ.openImage("") slices = [None, None] w = Weaver.inline( """ byte[] pix1 = (byte[]) slices.get(0); byte[] pix2 = (byte[]) slices.get(1);  byte[] xor = new byte[pix1.length]; for (int i=0; i<pix1.length; i++) { xor[i] = (byte)(pix1[i] ^ pix2[i]); } return xor; """, {"slices" : slices}) stack = imp.getStack()stackXOR = ImageStack(stack.width, stack.height) for i in range(2, imp.getNSlices()+1): # Put the pixel arrays into the pre-made list slices[0] = stack.getPixels(i-1) slices[1] = stack.getPixels(i) # Invoke native code stackXOR.addSlice( str(i-1), ) ImagePlus("XORed stack", stackXOR).show()</source> Of course the Weaver is a java library, and may be used from any scripting language such as [[Javascript Scripting|Javascript]], [[JRuby Scripting|JRuby]], and [[:Category:Scripting|others]]. All the above is inspired by the [ Scientific Python Weaver, or scipy Weaver], which inlines C code inside a python file. === Reading command line arguments given to a script === The Fiji launcher can execute scripts. When running scripts from the command line with the launcher, it is convenient to read out the arguments given to the script. For example, suppose you create a script to open an image file and do some processing with it, and you want to read the name of the file to open from the command line argument. Here is how: <source lang="python">import os, sysfrom ij import IJ # Expecting one argument: the file pathif len(sys.argv) < 2: print "Usage: ./fiji-linux64 <script-name> <file-path>" sys.exit(1) filepath = sys.argv[1] # Check if the file existsif not os.path.exists(filepath): print "File does not exist at path:", filepath sys.exit(1) # Open the imageimp = IJ.openImage(filepath)print "Processing:", imp.title # Do some processing ... </source> IMPORTANT: notice that, when executing scripts from the command line, there is no auto-importing of common imports. So above we <b>must</b> declare "from ij import IJ" to import the namespace <i>IJ</i> with all the static utility functions such as <i>openImage</i>. === Catching errors from a running macro === ImageJ exits with zero even when it fails (see [ bug report]). A possible fix is to convert the macro into a plugin but a quicker fix, is to wrap the macro call into a script. For this purpose, it is enough to check the returned string of <code>runMacroCode</code>, which will return the string <code>[aborted]</code> in case of [,%20java.lang.String%29 failure]: <source lang="python">from ij import IJimport sys
if not len (sys# Now you can import $FIJI_ROOT/bin/myModule.argv) > 1:py raise TypeError ("No macro file argument") status = IJ.runMacroFile(sys.argv[1])if status == '[aborted]': raise StandardError ("Macro execution failed") sys.exit (0)import myModule
Of course, if your macro happens to return The function <code>[aborted]getProperty()</code> for success, you're out of luck ;) === Running 3rd party java libraries === It is possible to run external java programs within Jythonaccepts many more strings. To make them available, just copy the corresponding jar file into Fiji's plugins folderA list can be found at [https://docs. To import the respective java classes, just do <source lang="python">import as foo<com/javase/tutorial/essential/environment/source>  If the class names of the external package are unknown, one possibility is to inspect the jar file manuallysysprop. On Linux and Mac OS systems just do on the command line <source> jar tvf <library>html The Java Tutorials].jar
</source>== Self written Jython packages for ImageJ ==
This will print On the jar contents as plain textway to perfectly organize Jython code, look for entries ending with "[https://docs.python.class"org/2/tutorial/modules. For html#packages packages] are the implementation of json in jythonnext step. In Jython, provided at jysonfolders that contain modules are made packages by adding the file <code></code>.xhausThis file can be, the output looks An folder structure can look likethis:
<source> tvf jyson-1.0.2- myModule.jarpy 0 Sat Mar 17 14:06:40 CET 2012 META-INF- myPackage/ 106 Sat Mar 17 14:06:38 CET 2012 META-INF/MANIFEST- __init__.MF 0 Sat Mar 17 14:06:40 CET 2012 com/ 0 Sat Mar 17 14:06:40 CET 2012 com/xhaus/ 0 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/py 174 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/JSONDecodeError-- mathTools.classpy 174 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/JSONEncodeError-- customFilters.classpy 162 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/JSONError-- fftTools.classpy 1650 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson-- myPackage2/JysonCodec.class 6350 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/JysonDecoder -- __init__.classpy 3899 Sat Mar 17 14:06:40 CET 2012 com/xhaus/jyson/JysonEncoder -- mathTools.classpy</source> The JysonCodec.class is the toplevel class, so to import this library include the following line in your jython script: <source lang="python">import com.xhaus.jyson -- stackProcessing.JysonCodec as jysonpy
[[Category:Scripting]][[Category:Jython]] == Jython for plugins == === Using a jython script as a plugin === There are two packages and one module. The simplest way is to place first package contains three modules and the jython script file into fiji/plugins/ folder or a subfolder, and it will appear in second package contains two modules. We can import the menus after running "'{{bc | Plugins | Scripting | Refresh Jython Scripts}}'" or "'{{bc | Help | Refresh Menus}}'", or modules on restarting Fiji.different ways:
If you want to have <source lang='python'># Import the Jython script show up in a place outside single module using the Plugins menu, just put the file into an appropriate subdirectory of fiji/plugins/Scripts/; for example, if you put a Jython script called into fiji/plugins/Scripts/File/New/, it will be available as {{bc | File | New | Animation}}.default name:import myModule
=== Distributing jython scripts in # Import mathTools from the first packageimport myPackage.mathTools# Use a function from the imported modulemyPackage.mathTools.jar file ===aFunction()
PLEASE NOTE: there is no need to do # Import mathTools from the following -- unless you want to bundle second packagefrom myPackage2 import mathTools# Use a couple of scripts in one function from the imported module without prefixing the packagemathTools. See entry above.aFunction()
The easiest way to distribute a (single) Jython script is to start the [[Script Editor]], open # Import customFilters from the Jython script first package and make the bundle with {{bc | File | Export rename itfrom myPackage import customFilters as filters# Use a function from customFilters.jar}}pyfilters.aFunction()
Alternatively -- or if you want to bundle multiple scripts -- you can do it the manual way: The whole idea is to be able to distribute an entire collection of scripts in a single .jar file, for best convenience. In this example, we create two jython scripts that we want to distribute in # Importing all module from a .jar file as plugins:packagefrom myPackage2 import *# The <i></i> script: <source lang="python">next line will failIJstackProcessing.logaFunction("Print this to the log window")
The reason for the last import to fail is the empty <code></code>.We have to define which modules of the package are imported when using <code>import *</code>. and This is done by setting the variable <code>__all__</code> at <icode></icode>. For <code>myPackage2</code> scriptthis line of code is needed:
<source lang="'python"'>ip __all__ = ByteProcessor(400["mathTools", 400)imp = ImagePlus("NewstackProcessing", ip)ip.setRoi(OvalRoi(100, 100, 200, 200))ip.setValue(255)ip.fill(ip.getMask())]
Place both scripts under a folder named <i>scripts/</i> Besides setting this variable, the file can contain normal Jython code that is executed on import.
You will need == Bundle packages in a tiny .java JAR file specifying a launcher PlugIn, such as:==
An interesting feature of Jython is to search for packages and modules inside of [ JAR files]. The folder structure from the last section can be modified by packing everything into a single <code>myPackages.jar<source lang="java"/code>package my;import ij.pluginThe name of the JAR file doesn't matter.PlugIn;import JythonAll imports work the same as explained before.Refresh_Jython_Scripts;
public class Jython_Launcher implements PlugIn {<source> public void run(String arg) { myPackages.jar -- -- myPackage/ -- -- -- new Refresh_Jython_Scripts() -- fftTools.runScript(getClass()py -- myPackage2/ -- __init__.getResourceAsStream(arg));py } --} --
Notice we place The advantage of this approach is that you can share your packages easily. For example you can upload the above JAR file under directory <i>my/</i>, packagedto an [[Update_Sites|update site]].  To compile it:  $ javac -classpath .:ij.jar:../jars/fiji-scripting.jar:../plugins/Jython_Interpreter.jar my/  (check that the path to the three jars that you need It is correct!)  Then we define the plugins.config file:  Plugins>My Scripts, "Print possible to log window", my.Jython_Launcher("/scripts/printerupload .py") Plugins>My Scripts, "Create image with a white circle", my.Jython_Launcher("/scripts/") Finallyto update sites too, we put all files in without packaging into a .jar file:  $ jar cf my_jython_scripts.The advantage of jar plugins.config my/Jython_Launcher.class scripts/*py Then, drop the jar file into fiji/plugins/ folder and run "Help - Update Menus", or restart fiji. Your scripts will appear under Plugins - My Scriptsare that they allow to define dependencies more systematically.
For clarity'''NB''' : Script implementing "ImageJ menu macro" and "utilitary scripts" that are used as imported modules in other macros '''should be packed in separate jar files''' ! Indeed, if not explicitly mentioned, this is a summary of the files jython interpreter only looks in the Jars/Lib folder: my/Jython_Launcherto import module, so the .java my/Jython_Launcher.class jar containing the "utilitary scripts" should be put there, while the jar containing the "ImageJ menu macro" can be put either in the Plugin or script/ scripts/ pluginsPlugin folder in order to appear in the ImageJ menu.config
Contrary to the scripts in Jars/Lib, the menu macro scripts are not compiled, and as explained above they can not be imported in other scripts since the Plugin folder do not reside in the Jython search path by default.
This is the reason why a given project is rather distributed in 2 different jar files as explained [ here].
=== Using maven to build packages ===
Notice, though, that <b>Using maven you don't need to do can automate the .jar packaging at all</b>of Jython code into JAR files. Just place the python scripts directly under fiji/plugins/My Scripts/ This approach is only recommended if you already use maven, as installing and they will appear in learning how to use maven is not worth the menus as regular pluginstime saving of automated packaging.
= Jython examples in Fiji =At GitHub you will find an [ example project] that you can use as a template. Just run <code>mvn package</code> and maven will generate a JAR file at the <code>target</code> directory.
*{{GitHub|repo=fiji|path=plugins/Examples/|labelLinks =Find Dimension of Raw Image}}*{{GitHub|repo=fiji|path=plugins/Examples/|label=Edit LUT As Text}}*{{GitHub|repo=fiji|path=plugins/Examples/|label=Delayed Snapshot}}*{{GitHub|repo=fiji|path=plugins/Examples/Command_Launchers/|label=Command Launcher GUI}}*{{GitHub|repo=fiji|path=plugins/Examples/|label=List all threads}}*{{GitHub|repo=fiji|path=plugins/Examples/|label=Chess}}
*{{GitHub[[Jython_Scripting_Examples|repo=fijiJython Scripting Examples]]* [[ImageJ2_Python_Scripts|path=plugins/ExamplesImageJ2 Python Scripts]]* [https:/TrakEM2_Example_Scripts/|label=Extract stack under AreaList}} in TrakEM2uzh.*{{GitHub|repo=fiji|path=pluginsch/Examples~acardona/TrakEM2_Example_Scriptsfiji-tutorial/|label=Set all transforms to identity}} for TrakEM2 objects.A Fiji Scripting Tutorial by Albert Cardona]*{{GitHub|repo=fiji|path=plugins[http:/Examples/TrakEM2_Example_Scripts/|label=Select All}} objects in TrakEM2cmci.*{{GitHub|repo=fiji|path=pluginsinfo/Examplesdocuments/TrakEM2_Example_Scripts120206pyip_cooking/|label=Measure AreaList}} in TrakEM2.python_imagej_cookbook Jython scripting cookbook]
= See also = References ==*Albert Cardona's crash course in [http:/<references / Jython scripting with Fiji]. *Jython for [[TrakEM2 Scripting]].>