Difference between revisions of "JavaScript Scripting"

(Importing packages and classes: Package -> Packages)
(multithreading example for javascript)
Line 105: Line 105:
 
... which prints all method names such as getStatistics isHyperStack etc. and fields like width and height (because there are public 'get' methods for it such as getWidth() and getHeight() .)
 
... which prints all method names such as getStatistics isHyperStack etc. and fields like width and height (because there are public 'get' methods for it such as getWidth() and getHeight() .)
  
== Advanced scripting ==
+
== Interfaces and anonymous classes ==
  
 
To create an ImageListener without declaring a new class that implements such java interface, simply use a function that will be mapped to all its methods (as long as they have the same signature, which they do in this case):
 
To create an ImageListener without declaring a new class that implements such java interface, simply use a function that will be mapped to all its methods (as long as they have the same signature, which they do in this case):
Line 138: Line 138:
  
 
See also an [http://pacific.mpi-cbg.de/wiki/index.php/Scripting_comparisons#In_Javascript example plugin] for ImageJ written in javascript.
 
See also an [http://pacific.mpi-cbg.de/wiki/index.php/Scripting_comparisons#In_Javascript example plugin] for ImageJ written in javascript.
 +
 +
== Multithreaded Image Processing in Javascript ==
 +
 +
The following example shows how to create a generic function, named <i>multithreader</i>, that accepts another function as argument and executes it in parallel a number of times. As a very simple example, a <i>printer</i> function is passed to the <i>multithreader</i>, and a list of numbers is printed without repeating anyone, and not preserving the order of course.
 +
 +
The <i>multithreader</i> scales up to as many CPU cores as the computer has to offer.
 +
 +
Always remember: only <b>completely</b> independent tasks can be parallelized effectively!
 +
 +
A good strategy for multithreading involves carefully considering the task to parallelize: how small can the chunks be? For an image, a chunk could be a pixel or a line, but often those are too small to overcome the overhead of parallelization.
 +
 +
See this complete plugin, the , which illustrates how to generate an image with random pixel values in a multithreaded manner, and how the choice of chunks to process in parallel is made.
 +
 +
Despite the simple example below, the <i>multithreader</i> framework function allows variable amount of arguments to be passed, as illustrated in the complete plugin [http://pacific.mpi-cbg.de/cgi-bin/gitweb.cgi?p=fiji.git;a=blob;f=plugins/Examples/Multithreaded_Image_Processing_in_Javascript.js;hb=HEAD Multithreaded_Image_Processing_in_Javascript.js]. The script shows how to generate an image with random pixel values in a multithreaded manner, and how the choice of chunks to process in parallel is made for reasonable effectiveness.
 +
 +
<source lang="javascript">
 +
// Now, abstract away the multithreading framework into a function
 +
// that takes another function as argument:
 +
 +
function multithreader(fun, start, end) {
 +
        var threads = new java.lang.reflect.Array.newInstance(java.lang.Thread, Runtime.getRuntime().availableProcessors());
 +
        var ai = new AtomicInteger(start);
 +
        // Prepare arguments: all other arguments passed to this function
 +
        // beyond the mandatory arguments fun, start and end:
 +
        var args = new Array();
 +
        var b = 0;
 +
        IJ.log("Multithreading function \"" + fun.name + "\" with arguments:\n  argument 0 is index from " + start + " to " + end);
 +
        for (var a = 3; a < arguments.length; a++) {
 +
                args[b] = arguments[a];
 +
                IJ.log("  argument " + (b+1) + " is " + args[b]);
 +
                b++;
 +
        }
 +
        var body = {
 +
                run: function() {
 +
                        for (var i = ai.getAndIncrement(); i <= end; i = ai.getAndIncrement()) {
 +
                                // Execute the function given as argument,
 +
                                // passing to it all optional arguments:
 +
                                fun(i, args);
 +
                                Thread.sleep(100);
 +
                        }
 +
                }
 +
        }
 +
        // start all threads
 +
        for (var i = 0; i < threads.length; i++) {
 +
                threads[i] = new Thread(new Runnable(body)); // automatically as Runnable
 +
                threads[i].start();
 +
        }
 +
        // wait until all threads finish
 +
        for (var i = 0; i < threads.length; i++) {
 +
                threads[i].join();
 +
        }
 +
}
 +
 +
// The actual desired effect: the printer
 +
function printer(i) {
 +
        IJ.log("i is " + i);
 +
}
 +
 +
// Execute:
 +
multithreader(printer, 0, 10);
 +
</source>
 +
 +
 +
See the complete file here: [http://pacific.mpi-cbg.de/cgi-bin/gitweb.cgi?p=fiji.git;a=blob;f=plugins/Examples/Multithreaded_Image_Processing_in_Javascript.js;hb=HEAD Multithreaded_Image_Processing_in_Javascript.js]
 +
  
 
= Links =
 
= Links =

Revision as of 16:18, 9 November 2008

Javascript tutorial for ImageJ

Language basics

Importing packages and classes

By default, all ImageJ and java.lang.* classes are imported.

You can specify further imports by:

// Import all classes under java.io.*
importPackage(Packages.java.io)

// Import a single class instead
importClass(Packages.java.io.File)

Creating import namespaces

 var awt_bindings = new JavaImporter(Packages.java.awt.Frame, Packages.java.awt.Button);
 
 with (awt_bindings) {
   // imported classes visible ONLY in this block
   win = new Frame("Title");
   b = new Button("Press me");
   win.add(b);
   win.pack();
   win.setVisible(true);
 }

Inspecting fields and methods of an object

So you are returned an object for a function and you don't know what is it.

To print its class within the interpreter:

 ob = ...
 ob.getClass();

or to the log window:

 ob = ...
 IJ.log(ob.getClass());

To print the list of methods it has, with their return types and argument types:

 ob = ...
 m = ob.getClass().getMethods();
 for (i=0; i<m.length; i++) IJ.log(m[i]);

ImageJ interaction

Opening and creating ImageJ images

 imp = new Opener().openImage("/path/to/image.jpg");
 // do some processing
 // ...
 imp.show();
 // from scratch:
 width = 512
 height = 512
 pixels = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, width * height);
 // process the pixels
 // ...
 channel = new java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 256);
 for (i=0; i<channel.length; i++) channel[i] = Integer(i).byteValue();
 cm = new LUT(channel, channel, channel);
 imp = new ImagePlus("the title", new ByteProcessor(width, height, pixels, cm));
 imp.show();
 // a bit less from scratch
 imp = ImagePlus("the title", new ByteProcessor(512, 512));
 pixels = imp.getProcessor().getPixels();
 // do some processing ...
 // ...
 imp.show();

Running ImageJ commands

To launch a command:

 // in a separate thread:
 IJ.doCommand("FFT");
 // instead, waiting until it finishes:
 IJ.run("FFT");

Inspect java methods and fields in an object

To print the static fields and methods of ImagePlus class:

 s = "";
 for (a in ImagePlus) { s += " " + a; }

... which prints INTEGRATED_DENSITY AREA_FRACTION etc.

To print the fields and methods of an instance of ImagePlus (i.e. an image that already exists):

 // get the current image
 imp = IJ.getImage();
 // print fields and methods
 s = ""; for (a in imp) { s += " " + a; }

... which prints all method names such as getStatistics isHyperStack etc. and fields like width and height (because there are public 'get' methods for it such as getWidth() and getHeight() .)

Interfaces and anonymous classes

To create an ImageListener without declaring a new class that implements such java interface, simply use a function that will be mapped to all its methods (as long as they have the same signature, which they do in this case):

 ImagePlus.addImageListener( function (imp, name) {
       if (name == "imageOpened") {
               IJ.log("Opened image: " + imp);
       } else if (name == "imageClosed") {
               IJ.log("Closed image: " + imp);
       } else if (name == "imageUpdated") {
               IJ.log("Updated image: " + imp);
       }
 });


Alternatively, one can create an object with declared functions inside to assign then to an anonymous class created on the fly from an interface:

 body = {
   run: function () {
     IJ.log("Running!");
   }
 }
 // Runnable is an interface
 runnable = new Runnable(body);
 new Thread(runnable).start();

Simplified:

 new Thread( function () { IJ.log("Running!"); } ).start();

What the code above did: to look for an interface that could take a method with no arguments, represented by the function, and instantiate an anonymous class that implements such interface with the function mapped to its method.

See also an example plugin for ImageJ written in javascript.

Multithreaded Image Processing in Javascript

The following example shows how to create a generic function, named multithreader, that accepts another function as argument and executes it in parallel a number of times. As a very simple example, a printer function is passed to the multithreader, and a list of numbers is printed without repeating anyone, and not preserving the order of course.

The multithreader scales up to as many CPU cores as the computer has to offer.

Always remember: only completely independent tasks can be parallelized effectively!

A good strategy for multithreading involves carefully considering the task to parallelize: how small can the chunks be? For an image, a chunk could be a pixel or a line, but often those are too small to overcome the overhead of parallelization.

See this complete plugin, the , which illustrates how to generate an image with random pixel values in a multithreaded manner, and how the choice of chunks to process in parallel is made.

Despite the simple example below, the multithreader framework function allows variable amount of arguments to be passed, as illustrated in the complete plugin Multithreaded_Image_Processing_in_Javascript.js. The script shows how to generate an image with random pixel values in a multithreaded manner, and how the choice of chunks to process in parallel is made for reasonable effectiveness.

// Now, abstract away the multithreading framework into a function
// that takes another function as argument:

function multithreader(fun, start, end) {
        var threads = new java.lang.reflect.Array.newInstance(java.lang.Thread, Runtime.getRuntime().availableProcessors());
        var ai = new AtomicInteger(start);
        // Prepare arguments: all other arguments passed to this function
        // beyond the mandatory arguments fun, start and end:
        var args = new Array();
        var b = 0;
        IJ.log("Multithreading function \"" + fun.name + "\" with arguments:\n  argument 0 is index from " + start + " to " + end);
        for (var a = 3; a < arguments.length; a++) {
                args[b] = arguments[a];
                IJ.log("  argument " + (b+1) + " is " + args[b]);
                b++;
        }
        var body = {
                run: function() {
                        for (var i = ai.getAndIncrement(); i <= end; i = ai.getAndIncrement()) {
                                // Execute the function given as argument,
                                // passing to it all optional arguments:
                                fun(i, args);
                                Thread.sleep(100);
                        }
                }
        }
        // start all threads
        for (var i = 0; i < threads.length; i++) {
                threads[i] = new Thread(new Runnable(body)); // automatically as Runnable
                threads[i].start();
        }
        // wait until all threads finish
        for (var i = 0; i < threads.length; i++) {
                threads[i].join();
        }
}

// The actual desired effect: the printer
function printer(i) {
        IJ.log("i is " + i);
}
 
 // Execute:
 multithreader(printer, 0, 10);


See the complete file here: Multithreaded_Image_Processing_in_Javascript.js


Links

See also the Scripting_comparisons.