User Tools

Site Tools


documents:110822jsip_cooking:javascript_imagej_cookbook

Javascript (+ ImageJ) Cookbook

For scripting with ImageJ and Fiji using Javascript, an concise introduction is available at the ImageJ website. An excellent tutorial could be found at the Fiji website. Assuming that you have done this tutorial already, I list some practical usage examples in below.

If you need more examples, Jython examples are recommended. Their usage of ImageJ Java classes provides many hints.

Data I/O

Getting Directory Path Interactively

dc = DirectoryChooser("Select an output folder...");
dir = dc.getDirectory();
IJ.log(dir);

Getting File Path Interactively

importClass(Packages.ij.io.OpenDialog);

od = new OpenDialog("Open As String", "");
directory = od.getDirectory();
name = od.getFileName();
path = directory + name;
IJ.log(path);

Path String Management

// Example code for managing path strings. 
// Kota Miura (miura@embl.de)
// ... assumes Unix style path
// ... assumes that the script is executed from command line. 
// ... argment should be in the form <a path>:<another path>

args = getArgument();
importClass(Packages.ij.util.Tools);
argA = Tools.split(args, ":");
IJ.log(argA[0]);
IJ.log(argA[1]);

fpA = Tools.split(argA[0], "/");
path = "/";
for (i in fpA){
	if (i != (fpA.length - 1))
		path = path + fpA[i] + "/";
	else
		file = fpA[i];
}
traindata =argA[1];
IJ.log(path);
IJ.log(file);
IJ.log(traindata);

https://github.com/miura/ijmacros/blob/master/PathStringManagement.js

Loading CSV file (data table)

Note that line 21 uses java.lang.String class explicitly, for using endsWith() method in the line 22. Otherwise the string variable “filepath” is a type of JS string which does not have endsWith() method.

// Example javascript for loading data from a series of CSV files in a folder.
// 
// Assumes that these files are data output from other processing, 
// and all data has same format. 
// This script uses openCSV, which is included in Fiji. 
// for more details on openCSV, visit the URLbelow. 
// http://opencsv.sourceforge.net/
// 20110822 Kota Miura (miura@embl.de) 

importPackage(Packages.util.opencsv);
importPackage(java.io);

//path = "/Users/miura/Dropbox/data"; //unix
path = "C:/dropbox/My\ Dropbox/data"; //win

dir = new File(path);
filesA = dir.list();
sp = File.separator;

for (var i=0; i<filesA.length; i++) {
	filepath = java.lang.String(dir + sp + filesA[i]);
	if (filepath.endsWith(".txt") || filepath.endsWith(".csv")) {
        	IJ.log(filepath);
        	readCSV(filepath);
	} else {
        	IJ.log("Igonored: " + filepath);
	}
}

// reads out 5th column in the CSV file
// using readALL method
function readCSV(filepath) {
	var reader = new CSVReader(new FileReader(filepath), " ");
	var ls = reader.readAll();
	var it = ls.iterator(); 
	while (it.hasNext()){
		var carray = it.next();
		IJ.log(carray[4]); 
	}
}

// reads out 5th column in the CSV file
// using readNext method, output is similar to readAll
function readCSVbyLine(filepath) {
	var reader = new CSVReader(new FileReader(filepath), " ");
	while ((nextLine = reader.readNext()) != null) {
        	// nextLine[] is an array of values from the line
        	IJ.log(nextLine[4]);
    	}    
}    

https://github.com/miura/ijmacros/blob/master/CSVloader.js

Saving CSV file (data table)

This example is in Jython (Python style Java scripting).

from util.opencsv import CSVWriter
from java.io import FileWriter
from java.lang.reflect import Array
from java.lang import String, Class
 
writer = CSVWriter(FileWriter("c:/temp/testcsv.csv"), ',')
data = Array.newInstance(Class.forName("java.lang.String"), 3)
#String[] entries = "first#second#third".split("#");
data[0] = str(11)
data[1] = str(23)
data[2] = str(5555)
writer.writeNext(data)
writer.close()

Bitwise AND

Bitwise AND is often used as switching ON/OFF multiple options. For Example:

DISPLAY_SUMMARY = 256;
SHOW_ROI_MASKS = 4096;
options = SHOW_ROI_MASKS + DISPLAY_SUMMARY;
if ((options&SHOW_ROI_MASKS)!=0)
	IJ.log("SHOW_ROI_MASKS selected");

Switching ON/OFF is controlled using 16bit binary a.k.a 16 digit binary number. 256 is

0000000100000000

9th digit from the right is “1”, the place where ON/OFF of DISPLAY_SUMMARY is controlled. 4096 is

0001000000000000

13th digit controls the ON/OFF of SHOW_ROI_MASKS. If you need to turn these options on,

0001000100000000

both 9th and 13th digits should be 1. To construct this binary number, it simply is:

256 + 4096 = 4352
bin(4352) = 0001000100000000

To check if “options” (a number) contains SHOW_ROI_MASKS, one compares if corresponding digit (13th) is turned ON. To do so, we use Bitwise AND.

(0001000100000000)
AND
(0001000000000000)

result: 0001000000000000

meaning that

((options&SHOW_ROI_MASKS)!=0)

is true.

Above is a short example made for showing how to control ParticleAnalyzer options.

Arguments of Function could be with Variable Length

Javascript Function is a class that takes variable length of arguments. Even if there is no arguments declared in the function, one could add ones in runtime and could be retrieved from inside the function using Functions object 'Arguments'.

// normal way of writing function 
function add01(a, b) {
  return a+b;
}

//using 'argument' object of class Function
function add02(a, b) {
  return arguments[0] + arguments[1];
}

IJ.log(add01(1, 2)); // prints 3
IJ.log(add02(1, 2)); // prints 3 as well

IJ.log("------");

// a bit more with arguments
// to show that 'arguments' could be with any length
function sum() {
  var result = 0;
  for (var i = 0, n = arguments.length; i < n; i++) {
    result += arguments[i];
  }
  return result;
}

IJ.log(sum(1, 2, 3)); // prints 6
IJ.log(sum(1, 2, 3, 4, 5, 6)); // prints 21

Writing Values in the Results Table

rt = ResultsTable();
for (var i = 0; i < 10; i++){
	rt.incrementCounter();
	rownum = rt.getCounter()-1;
	rt.setValue("testcol", rownum, Double.valueOf(i*i));	
}
rt.show("Results");

Aborting the script

To abort the running script, use the following function. I got this from here.

function javascript_abort(){
   throw new Error('This is not an error. This is just to abort javascript');
}

Arrays

Converting Java array to javascript array

Keep in mind that java array and Javascript array are different types.

For some array treatments, this matters a lot and keeping your arrays either Java array or Javascript array is pretty important. Below is an example of Java > javascript array conversion and also how to check the object type. For constructing Java array in javascript, see here.

//as an example, you first get an array from 
//Results table in ImageJ. 
// this array is Java array.
 
rt = ResultsTable.getResultsTable();
sliceA = rt.getColumn(rt.getColumnIndex("Slice"));

//converting java array to javascript array

sliceJSA = [];
for (var i =0; i < sliceA.length; i++)
	sliceJSA.push(sliceA[i]);

//check object types 
IJ.log("sliceA class: " + Object.prototype.toString.call(sliceA));
IJ.log("sliceJSA class: " + Object.prototype.toString.call(sliceJSA));

Sorting Numerical Array

//prepare some data
data = [10.0, 100.0, -1.0, 9.0, 200.0, 1.0];

data.sort();

IJ.log(data.valueOf()); //prints -1,1,10,100,200,9

// Comparator should be created.
//here we go again
 
data = [10.0, 100.0, -1.0, 9.0, 200.0, 1.0];

// create a comparator
function comp(a, b){
	return (a - b); 
}

data.sort(comp);

IJ.log(data.valueOf()); //prints -1,1,9,10,100,200

Sorting a List of Numbered Files

Consider a situation of having a list of file names in an array filesA in the follwoing order, and we want to sort the name so the numbering is in ascending order.

110608wt2.tif.proc.tif.noseg.tif8_9.txt
110608wt2.tif.proc.tif.noseg.tif9_10.txt
110608wt2.tif.proc.tif.noseg.tif10_11.txt
110608wt2.tif.proc.tif.noseg.tif0_1.txt
110608wt2.tif.proc.tif.noseg.tif1_2.txt
110608wt2.tif.proc.tif.noseg.tif2_3.txt
110608wt2.tif.proc.tif.noseg.tif3_4.txt
110608wt2.tif.proc.tif.noseg.tif4_5.txt
110608wt2.tif.proc.tif.noseg.tif5_6.txt
110608wt2.tif.proc.tif.noseg.tif6_7.txt
110608wt2.tif.proc.tif.noseg.tif7_8.txt

Such sorting could be done by combining regular expression matching.

importPackage(java.io);
path = "c:\\files";
dir = new File(path);
filesA = dir.list();
sp = File.separator;

filesA.sort(comparator);

for (var i=0; i<filesA.length; i++) {
	filepath = java.lang.String(dir + sp + filesA[i]);
	if (filepath.endsWith(".txt")) 
        	IJ.log(filesA[i]);
  	else
  		IJ.log("Igonored: " + filepath);
}

function comparator(stra, strb){
        // regular expression to extract numberings
	var patt1 = /\.tif([0-9]{1,10})_/i;
	regexa = stra.match(patt1);
	regexb = strb.match(patt1);	
	return (regexa[1] - regexb[1]) 
}

Above code will then prints out:

110608wt2.tif.proc.tif.noseg.tif0_1.txt
110608wt2.tif.proc.tif.noseg.tif1_2.txt
110608wt2.tif.proc.tif.noseg.tif2_3.txt
110608wt2.tif.proc.tif.noseg.tif3_4.txt
110608wt2.tif.proc.tif.noseg.tif4_5.txt
110608wt2.tif.proc.tif.noseg.tif5_6.txt
110608wt2.tif.proc.tif.noseg.tif6_7.txt
110608wt2.tif.proc.tif.noseg.tif7_8.txt
110608wt2.tif.proc.tif.noseg.tif8_9.txt
110608wt2.tif.proc.tif.noseg.tif9_10.txt
110608wt2.tif.proc.tif.noseg.tif10_11.txt

To study more about Javascript regular expression, maybe visit here.

Getting the Minimum and the Maximum value of Javascript array

I thought of Math.max(array.valueOf()) seemingly should work, but it doesn't. It should be like this:

var testa = Array();

testa[0] = 10.3;
testa[1] = 20.1;
testa[2] = 100.9;
testa[3] = 5.1;

minval = Math.min.apply(Math, testa);
maxval = Math.max.apply(Math, testa);
IJ.log("Minimum value: " + minval);
IJ.log("Maximum value: " + maxval);

This is because Math.min and Math.max methods only takes individual numbers, not an array. To unpack an array, apply() method of class Function is used. An example below depicts its usage.

 
var sum = function(){
  var result = 0;
  for (var i = 0, n = arguments.length; i < n; i++) {
    result += arguments[i];
  }
  return result;
};

data01 = [1, 2, 3];
data02 = [1, 2, 3, 4, 5, 6];

ans = sum.apply(sum, data01);
IJ.log(ans);

ans = sum.apply(sum, data02);
IJ.log(ans);

… I mean if you want to sum up, you don't really have to be bulky but method apply() has so many flexibility in applying methods to any objects.

Apply function to Each Element of Array

Use Array.forEach(function) method.

data = [10.0, 100.0, -1.0, 9.0, 200.0, 1.0];

data.forEach(printArray);
IJ.log("---")
data.forEach(squaredArray);

function printArray(x, idx) {
   IJ.log('['+idx+'] = '+x);
}

function squaredArray(x, idx) {
   IJ.log('['+idx+'] = '+ Math.pow(x,2));
}

Output:

[0] = 10
[1] = 100
[2] = -1
[3] = 9
[4] = 200
[5] = 1
---
[0] = 100
[1] = 10000
[2] = 1
[3] = 81
[4] = 40000
[5] = 1

Source array is not affected in this case. If you want to modify the array itself, use Array.map(function) examples in the following. See more examples at this site.

Object Oriented processing of Arrays using Array.map()

map() function is convenient if you want to have an output array after processing each element.

// this will be an example array
xA = [5, 25, 75, 100];

// create an object with a field 'factor' and a method 'multiply'
var obj = {
	factor: 2,
	multiply: function (x){
		return x * this.factor;
	}
}
// ... factor 2 will then be the default value. 

//use Array.map(function, obj) to calculate all elements at once. 

array = xA.map(obj.multiply, obj);
IJ.log(array.join()); // prints 10,50,150,200

//replace the factor.
obj.factor = 4;

array = xA.map(obj.multiply, obj);
IJ.log(array.join()); //prints 20,100,300,400

Slicing Multidimensional Array

Here are examples of horizontal and vertical slicing of a 2D array. Vertical slicing is a bit complex, but I could not figure out other ways. If you know one, please tell me. What supposed to be something like v1 = allA[:, 1] in Python would be much easier.

//multidimensional array slicing

print = IJ.log;

xA = [1, 2, 3];
yA = [40, 50, 60];
zA = [-1, -2, -3];
allA = [xA, yA, zA];	//this is a multidimensional array

print(allA[1][2]);	//prints 60
print(allA[1]);		//prints 40,50,60, (sliced horizontally)

v1 = allA.map(function (v){return v[1];});//(sliced vertically)
print(v1);		//prints 2,50,-2  
print(v1[2]);		//prints -2

//--- here is another way of vartical slicing, 
// longer but more clear with what's happening. 

var obj = {sliceindex:1}; //prepare an aboject with variable
v1 = allA.map(returnVert, obj); //use map function returnVert(see below)
				//with context of object 'obj'
                                //prints three lines of 'slice index:1' during map exexution
print(v1);         //prints 2,50,-2



// v: one dimensional array passed from map function
// id: index of the one dimensional array passed, within
//	the multidimensional array
// a: parent array (= itself, in our case allA)
function returnVert(v, id, a){
	print("slice index:" + this.sliceindex); //this.sliceindex will be passed from obj
	return a[id][this.sliceindex];
}

Matrix Transpose

An application of vertical slicing, matrix transposition.

//transposing data matrix

function transp(incoords){
	var transposed = [] 
//	for(var i = 0; i < incoords[0].length; i++){
	for(var i in incoords[0]){
		transposed.push(incoords.map(function(v){return v[i];}));
	}
	return transposed;
}

data = [	[0, 1, 2],
		[3, 4, 5],
		[6, 7, 8]];

var tdata = transp(data);

for (i in data) IJ.log(data[i]);
/* prints
0,1,2
3,4,5
6,7,8
*/
for (i in tdata) IJ.log(tdata[i]);
/* prints
0,3,6
1,4,7
2,5,8
*/

Windows

Duplicating current Results table with different title

ResultsTable.getResultsTable().clone().show("duplicated");

Activating / Deactivating BatchMode

To suppress creation of image windows, you could activate BatchMode. Corresponding function in ImageJ is setBatchMode(true) and setBatchMode(false).

importClass(Packages.ij.macro.Interpreter);
macro = new Interpreter(); 

// activate batchmode (= setBatchMode(true) in IJ macro)
macro.batchMode = true;

//when error occurrs and execution is terminated during batchmode=true, 
//you might not see any images anymore (even if you try to open a new one manually). 
// To avoid, do something like below to catch error and deactivate the batchmode. 
try {
	IJ.run(imp, "do process...", op);
catch(err){
		macro.batchMode = false;
		IJ.log("!Error with do process...");
		IJ.log(err.rhinoException.toString());
		IJ.log(err.javaException.toString());		
}

//deactivate batchmode
macro.batchMode = false;

Closing All Image Windows

function imagewinKiller(){
	var wins = WindowManager.getIDList();
	for (var i = 0; i < wins.length; i++)
		WindowManager.getImage(wins[i]).close();
}

Adding Mouse Listener to an Image

// example of implementing and extending java interface

importPackage(java.awt.event);

// extends MouseAdapter, implements MouseMotionListener
var mouseListener = new JavaAdapter(MouseAdapter, MouseMotionListener, {
    mouseClicked: function(event) {
        IJ.log("clicked" + " (" + event.getX() + "," + event.getY() + ")");
    },
    mouseDragged: function(event) {
        IJ.log("dragged");
    },
    mouseMoved: function(event) {
    }
});

imp = IJ.getImage();
var win = imp.getWindow();

win.getCanvas().addMouseListener(mouseListener);
win.getCanvas().addMouseMotionListener(mouseListener);

As of 20131120, above code works with “Run” in Fiji script editor, but it DOES NOT work if you save the script as a file and run it using [Macro > Plugins > Run]. This probably is caused by the difference in javascript engine version: Fiji script editor uses jar/js.jar, but the latter method uses JS evaluator packaged with JRE. Following code works with [Macro > Plugins > Run…]. Difference is that the constructor for JavaAdaptor in this case uses two arguments, rather than three arguments. This problem was pointed out by Torsten Stöter (Uni. Magdeburg) and following fix was contributed by him. Thanks to Torsten!

var mouseListener = new JavaAdapter(MouseListener, /*MouseMotionListener,*/ {
    mouseClicked: function(event) {
        IJ.log("clicked" + " (" + event.getX() + "," + event.getY() + ")");
    },
    mouseDragged: function(event) {
        IJ.log("dragged");
    },
    mouseMoved: function(event) {
    }
});

Adding Overlays to an Image

An example of overlay function in ImageJ / Fiji.
For drawing Arrows, use commented out lines.

overlayLine(10, 10, 40, 40);
overlayLine(40, 40, 10, 70);

function overlayLine(x1, y1, x2, y2){
	importClass(Packages.ij.gui.Overlay);
	importClass(Packages.java.awt.Color);
	imp = IJ.getImage();
//roi1 = Arrow( 110, 245, 111, 246);
	roi1 = Line(x1, y1, x2, y2);
//roi1.setWidth(1.5);
//roi1.setHeadSize(3);
	imp.setRoi(roi1);
	overlay = imp.getOverlay();
	if (overlay != null)
		overlay.add(roi1);
	else
		overlay = Overlay(roi1);
	red = Color(1, 0, 0);
	overlay.setStrokeColor(red); 
	imp.setOverlay(overlay);
	imp.updateAndDraw() ;

//IJ.log("head " + roi1.getDefaultHeadSize());
//IJ.log("head " + roi1.getDefaultWidth());
}

Image Processing

Creating a Partial Stack of an Original Stack with shared ImageProcessor objects

function alias2frames(imp, i){
	var stack = imp.getStack();
	var tempstk = new ImageStack(imp.getWidth(), imp.getHeight());
	tempstk.addSlice(String(i), stack.getProcessor(i).clone());
	tempstk.addSlice(String(i+1), stack.getProcessor(i+1).clone());
	var imp2 = new ImagePlus("temp", tempstk);	
	return imp2	
}

Background Subtraction by ImageMath

//Example Javascript for Background substraction using ImageMath 
// Kota Miura (miura@embl.de)

//get ImagePlus of the active window
imp = IJ.getImage();

//duplicate and blurr images
blurrimp = imp.duplicate();
IJ.run(blurrimp, "Gaussian Blur...", "sigma=15 stack");

//subtract the blurred from the original
ic = new ImageCalculator();
for (var i=1; i<=imp.getStackSize(); i++){
	imp.setSlice(i);
	blurrimp.setSlice(i);
	ic.run("Subtract", imp, blurrimp);
}

https://github.com/miura/ijmacros/blob/master/ImageMath.js

Batch Trainable Segmentation using Trained Data

// Example script for using trainable segmentation
// -- assumes that an extra plugin by Kota is installed
// -- assumes that you already have "trained data" arff
// 20110819
// Kota Miura (miura@embl.de)

// get currently active image / image stack
imp = IJ.getImage();

//path to the arff data
traindata = "D:\\People\\Tina\\20110813\\data02.arff";

importClass(Packages.emblcmci.DotSegmentByTrained);
dbt = new DotSegmentByTrained(traindata, imp);
binimp = dbt.runsilent();
binimp.show();

https://github.com/miura/ijmacros/blob/master/TrainableSegmentationByTrained.js

Another version without using the plugin above.

importClass(Packages.trainableSegmentation.WekaSegmentation);
imp = IJ.getImage();
ws = WekaSegmentation(imp);
ws.loadTrainingData('C:\\t\\data.arff');
if (ws.trainClassifier()){
	impout = ws.getClassifiedImage();
	if (impout == null) 
		IJ.log("failed retrieving output");
	else {
		impout.show();
	}
}	

Using 3D processor plugin

3D processing generally consumes long long time for calculation, so better been done silently and headlessly. Here is one recipe using 3D processor plugin, which could be a good hint for doing it in headless (batch) mode. Does not use IJ.rin method, so ImagePlus instance is handed over explicitly.

%gist(1663061)%

https://gist.github.com/miura/1663061

importClass(Packages.ij3d.image3d.IntImage3D);
imp=IJ.getImage();
ima=new IntImage3D(imp.getStack());
r=3;
ima2=ima.createLocalMaximaImage(r,r,r, true);
plus=new ImagePlus("localmaxima",ima2.getStack());
plus.show();

Transformation of 3D stack according to given landmark pairs

Works in Fiji. Note the use of JavaImporter() from line 12 to 15 for avoiding conflicts in name space.

//  affinetransform3D.js
//  Created: 201107120 by Kota Miura (CMCI, EMBL miura@embl.de)
//
// 	Collaborater: Oleg
//
// written according to the advice from Stephan Saalfeld@mpicbg
// http://groups.google.com/group/fiji-users/browse_thread/thread/4e70cd4caf96d180
// TODO try using moving least square. 
// http://pacific.mpi-cbg.de/javadoc/mpicbg/models/MovingLeastSquaresTransform.html
// http://www.ini.uzh.ch/~acardona/api/mpicbg/trakem2/transform/MovingLeastSquaresTransform.html
importPackage(Packages.java.util);
var mpimodel  = new JavaImporter();
var trakmodel = new JavaImporter();
var mpistack  = new JavaImporter();
var jarray    = new JavaImporter();
mpimodel.importPackage(Packages.mpicbg.models);
trakmodel.importPackage(Packages.mpicbg.trakem2.transform);
mpistack.importPackage(Packages.mpicbg.ij.stack);
jarray.importPackage(Packages.java.lang.reflect);

pointPairs = new ArrayList();
testFillPoints(pointPairs);

//LS fitting
modelM = new trakmodel.AffineModel3D();	//use Albert's class, for printing out matrix
modelM.fit( pointPairs );
IJ.log(modelM.toDataString());

// --- preparing target stack size, offsets ---

imp = IJ.getImage();	// move this later to the beginning to check if there is indeed an image stack opened
ww  = imp.getWidth();
hh  = imp.getHeight();
dd  = imp.getImageStackSize();

// need to use java native array for estimateBounds() method.
minA = jarray.Array.newInstance(java.lang.Float.TYPE, 3);
maxA = jarray.Array.newInstance(java.lang.Float.TYPE, 3);

minA[0] = 0.0;
minA[1] = 0.0;
minA[2] = 0.0;
maxA[0] = ww;
maxA[1] = hh;
maxA[2] = dd;

IJ.log("original:"+ ww.toString() +"," + hh.toString()+ "," + dd.toString()); 

destsizeA = ReCalcStackSize(modelM, minA, maxA);

ww = destsizeA[0];
hh = destsizeA[1];
dd = destsizeA[2];

for (var i in minA) IJ.log(minA[i]);
for (var i in maxA) IJ.log(maxA[i]);

outstr = "after: ";
for (var i in minA) outstr = outstr + destsizeA[i] + ",";
IJ.log(outstr);

ReCalcOffset(modelM, minA);
IJ.log(modelM.toDataString());

// --- stack transformation ---

mapping = mpistack.InverseTransformMapping( modelM );

ip =  imp.getStack().getProcessor( 1 ).createProcessor( 1, 1 ); 
target = new ImageStack(ww, hh);
for ( var s = 0; s < dd; ++s ) { 
  ip = ip.createProcessor( ww, hh ); 
  mapping.setSlice( s ); 
  try { 
    mapping.mapInterpolated( imp.getStack(), ip ); 
  } catch ( err ) { 
    alert('An error has occurred: '+err.message); 
  } 
  target.addSlice( "", ip ); 
}
impout = ImagePlus("out", target);
impout.show();


function testFillPoints(pointPairs) {
  var p11 = [1, 0, 0];
  var p12 = [0, 1, 0];

  var p21 = [0, 1, 0];
  var p22 = [0, 0, 1];

  var p31 = [0, 0, 1];
  var p32 = [1, 0, 0];

  var p41 = [0.5, 0, 0];
  var p42 = [0, 0.5, 0];

  pointPairs.add(mpimodel.PointMatch(mpimodel.Point(p11), mpimodel.Point(p12)));
  pointPairs.add(mpimodel.PointMatch(mpimodel.Point(p21), mpimodel.Point(p22)));
  pointPairs.add(mpimodel.PointMatch(mpimodel.Point(p31), mpimodel.Point(p32)));
  pointPairs.add(mpimodel.PointMatch(mpimodel.Point(p41), mpimodel.Point(p42)));
  IJ.log(pointPairs.toString());
}

function ReCalcStackSize(transM, minA, maxA){
  transM.estimateBounds(minA, maxA);
  var newsizeA = [0.0, 0.0, 0.0];  
  for (var i in newsizeA) 
    newsizeA[i] = Math.ceil(maxA[i] - minA[i]);
  return newsizeA;
}

function ReCalcOffset(transM, minA){
  var shift = new mpimodel.TranslationModel3D();
  var shift.set( -1*minA[0], -1*minA[1], -1*minA[2] );
  transM.preConcatenate(shift);
}

https://github.com/miura/ijmacros/blob/master/affinetransform3Dv2.js

3D tracking of spots, and plotting of the resulted spots in a new Stack

/*
* script for creating a stack with same size of the current stack, and plot xyz dots listed in results window.\
*
* Kota Miura
*/

imp = IJ.getImage();
impdimA = imp.getDimensions();


pt = IJ.runPlugIn(imp, "mosaic.plugins.ParticleTracker3DModular_", "radius=3 cutoff=3 percentile=0.01 link=2 displacement=10");
pt.transferParticlesToResultsTable();

//imp2 = imp.createImagePlus();
ims = imp.createEmptyStack();
for (var i = 0; i < impdimA[3]; i++) 
	ims.addSlice(i, new ByteProcessor(impdimA[0], impdimA[1]));
imp2 = new ImagePlus("test", ims);

nSlices = imp2.getNSlices();

rt = ResultsTable.getResultsTable();
xindex = rt.getColumnIndex("x"); 
yindex = rt.getColumnIndex("y"); 
zindex = rt.getColumnIndex("z");
xA = rt.getColumn(xindex);
yA = rt.getColumn(yindex);
zA = rt.getColumn(zindex);
for (var i = 0; i < xA.length; i++){
	IJ.log(xA[i]);
	cslice=Math.round(zA[i])+1; //z seems to statrt from 0 in tracker result, so add 1.
	if ((cslice > 0) && (cslice <= nSlices)) {
		ip = imp2.getStack().getProcessor(cslice);
		//ip.setColor(255);
		//ip.drawOval(Math.round(yA[i]), Math.round(xA[i]), 1, 1); //x and y is inverted.
		ip.set(Math.round(yA[i]), Math.round(xA[i]), 255); //x and y is inverted.

	}
}
imp2.show();

https://github.com/miura/ijmacros/blob/master/3Ddots.js

Math

Statistics using Apache Commons Math

Below is an example of calculating statistical values using Apache Commons Math library (already included in Fiji). There are many more you could do with it so explore the API.

//first example, using static methods "StatUtils". 
importClass(Packages.org.apache.commons.math.stat.StatUtils);
 
test = [1 , 3, 4, 8, 100];
IJ.log(test[2]);
mn = StatUtils.mean(test);
IJ.log(mn);

//above static method is limited with number of things that could be done. 
//use DescriptiveStatistics then (but consumes more memory)
importClass(Packages.org.apache.commons.math.stat.descriptive.DescriptiveStatistics);

stats = new DescriptiveStatistics();

// Add the data from the array
for(i = 0; i < test.length; i++) {
        stats.addValue(test[i]);
}

// Compute some statistics
mean = stats.getMean();
std = stats.getStandardDeviation();
median = stats.getPercentile(50);

IJ.log(mean);
IJ.log(std);

3D vector

Using 3D vector class in apache commons math.

importClass(Packages.org.apache.commons.math.geometry.euclidean.threed.Vector3D);

//construct 2 vectors
va = new Vector3D(0.0, 0.0, 2.0);
vb = new Vector3D(2.0, 0.0, 0.0);

//angle between va and vb 
ang = Vector3D.angle(va, vb);
IJ.log(ang);

//add va and vb, and out puts a new vector as a result
vc = new Vector3D(1.0, va, 1.0, vb);

//prints out elements of the vector vc
IJ.log("" + vc.getX()+ "," + vc.getY()+ "," + vc.getZ());

//dot (inner) product of va abd vb
dp = va.dotProduct(vb);
IJ.log(dp);

//cross product of va abd vb
vd = va.crossProduct(vb);
IJ.log("" + vd.getX()+ "," + vd.getY()+ "," + vd.getZ());

Solving Quadratic Formula

For this, I borrowed a code by Gary Jones published in

http://code.garyjones.co.uk/category/javascript/

//Solving quadratic formula
/**
 * Rounds number to "dp" decimal places.
 *
 * @author Gary Jones
 * @link http://code.garyjones.co.uk/category/javascript/
 */
function chop(number, decimal_places)
{
	var multiplier = Math.pow(10, decimal_places) // makes multiplier = 10^decimal_places.
	number = ( Math.round( number * multiplier ) ) / multiplier;
/*	if ( document.layers ){ // Tidies Netscape 4.x appearance.
		if ( number < 1 && number >= 0 ) number = "0" + number; // makes .752 to 0.752
		if ( number < 0 && number >-1 ) number = "-0" + number * -1 // makes -.367 to -0.367
	}
*/	return number;
}

/**
 * Finds two roots.
 *
 * For ax^2 + bx + c = 0, use quadratic("a", "b", "c", "+") and quadratic("a", "b", "c", "-").
 */
function quadratic(aq, bq, cq, root)
{
	var complex,
		lambda,
		lambdaone,
		lambdatwo,
		plusminusone,
		plusminustwo,
		bsmfac = bq * bq - 4 * aq * cq,
		precision = 3;
	if ( bsmfac < 0 ) { // Accounts for complex roots.
		plusminusone = " + ";
		plusminustwo = " - ";
		bsmfac *= -1;
		complex = Math.sqrt( bsmfac ) / ( 2 * aq );
		if ( aq < 0 ){ // if negative imaginary term, tidies appearance.
			plusminusone = " - ";
			plusminustwo = " + ";
			complex *= -1;
		}
		lambdaone = chop( -bq / ( 2 * aq ), precision ) + plusminusone + chop( complex, precision ) + 'i';
		lambdatwo = chop( -bq / ( 2 * aq ), precision ) + plusminustwo + chop( complex, precision ) + 'i';
	} else if ( 0 == bsmfac ){ // Simplifies if b^2 = 4ac (real roots).
		lambdaone = chop( -bq / ( 2 * aq ), precision );
		lambdatwo = chop( -bq / ( 2 * aq ), precision );
	} else { // Finds real roots when b^2 != 4ac.
		lambdaone = (-bq + (Math.sqrt( bsmfac ))) / ( 2 * aq );
		lambdaone = chop( lambdaone, precision );
		lambdatwo = (-bq - (Math.sqrt( bsmfac ))) / ( 2 * aq );
		lambdatwo = chop( lambdatwo, precision );
	}
	( '+' == root ) ? lambda = lambdaone : lambda = lambdatwo;
	return lambda; // Returns either root based on parameter "root" passed to function.
}

https://github.com/miura/ijmacros/blob/master/roiProfileGaussFitterV3.js

Gaussian fitting of Intensity Profile

In the second function, profileA is an array with intensity profile, and doPlot is an boolean flag for plotting the curve fitting result.

Note Line 18 and 19, where type conversion between Java array and javascript array is done.

// cf: class CurveFitter
// cfp: fitted parameter array
// estD: estimated diameter
function PlotFitted(xA, yA, cf, cfp, estD){
 var fitA = [];
 for (i in yA)
  fitA[i] = cf.f(cfp, i);
 fitplot = Plot("fitted", "pixels", "intensity", xA, fitA)
 fitplot.addPoints(xA, yA, fitplot.CIRCLE)
 fitplot.addLabel(0.1, 0.1, estD)
 fitplot.show()
} 

//returns diameter and goodness of fit in addition to the fit results parameters. 
function GaussFitReturnPara(profileA, doPlot){
  //var pixx = [];
  var resultsA = [];
  var pixx = java.lang.reflect.Array.newInstance(java.lang.Double.TYPE, profileA.length);
  for (var i=0; i<profileA.length ; i++) pixx[i] = Number(i); 
  cf = new CurveFitter(pixx, profileA);
  cf.doFit(cf.GAUSSIAN);
  IJ.log(cf.getResultString()); //debugging
  cfp = cf.getParams();
  //diameter = 2.355*cfp[3]; half max
  diameter = 4*cfp[3];	// 2*sigma 
  EstimatedDiameter = "Diameter =" + diameter;
  IJ.log("Goodness of Fit (1.0 is the best): " + cf.getFitGoodness());
  IJ.log("Estiamted Diameter = " + diameter);
  if (doPlot) PlotFitted(pixx, profileA, cf, cfp, EstimatedDiameter);

  var resA = HashMap();
  resA.put(headerA[0], cf.getIterations());
  resA.put(headerA[1], cf.getRestarts());
  resA.put(headerA[2], sqsum(cf.getResiduals()));
  resA.put(headerA[3], cf.getSD());
  resA.put(headerA[4], cf.getRSquared());
  resA.put(headerA[5], cf.getFitGoodness());
  resA.put(headerA[6], diameter);
  return resA;  
}

https://github.com/miura/ijmacros/blob/master/roiProfileGaussFitterV3.js

3DViewer

3DViewer has many capability in plotting 3D scenes, including time series. Api is available at here. Examples could be found in the website.

Checking Java3D version

Version of Java3D is a critical issue for programming 3DViewer. Since upgrading Java does not in many cases means automatic upgrading of Java3D in your Java extension folder, this could be a problem during development. Here is a way to check your Java3D version.

%gist(1663134)% [gist cmci/1663134]

Plotting Mesh shapes: an example with tubes

3D viewer Tube example

I use tubes for plotting trajectories. Here is an example. It seems that there will be newer class called customnode.Tube becoming available soon (as of 20111219). Since Point3d class is directly used in this new class, I will replace the code below, but this old one might still is informative as an example of using Java array.

// test for Mesh_Maker,createTube

importClass(Packages.java.util.Vector);
importPackage(Packages.ij3d);
importClass(Packages.customnode.CustomTriangleMesh);
importClass(Packages.javax.vecmath.Color3f);

col = Color3f(0, 1.0, 0.5);
col2 = Color3f(1.0, 0, 0);
colw = Color3f(1.0, 1.0, 1.0);

var xA = javaArray(1, 10);
var yA = javaArray(1, 10);
var zA = javaArray(1, 10);
var rA = javaArray(1, 1);
var tube = Mesh_Maker.createTube(xA, yA, zA, rA, 20, false);
var xA = javaArray(10, 20);
var yA = javaArray(10, 20);
var zA = javaArray(10, 10);
var rA = javaArray(1, 1);
var tube2 = Mesh_Maker.createTube(xA, yA, zA, rA, 20, false);
var tubes = Vector();		
tubes.addAll(tube);
tubes.addAll(tube2);
var csp = CustomTriangleMesh(tubes, colw, 0.0);
var ccs = ContentCreator.createContent(csp, "tubetime test", 0);
univ = new Image3DUniverse();
univ.show();
univ.addContent(ccs);
			
function javaArray(sp, ep){
	ja = new java.lang.reflect.Array.newInstance(java.lang.Double.TYPE, 2);
	ja[0] = sp;
	ja[1] = ep;
	return ja;
}

Plotting of tracks
documents/110822jsip_cooking/javascript_imagej_cookbook.txt · Last modified: 2020/11/26 08:24 by kota

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki