Micro-Manager 2.0 (Java) API


Move through this tutorial using the arrow keys.

Code is in grey color.

Try to write the requested lines or scripts yourself, before looking at one of the many possible solutions. Use the web resources to find the appropriate functions. If you can not easily figure things out, do not hesitate to look at the answer, and use the example given to make your code work.

Micro-Manager 2.0 (Java) API

The Micro-Manager object (usually named "mm”, but sometimes called “studio”) is organized in various “managers”, such as the “AcquisitionManager”, and “SnapLiveManager”, that contain functions executing most of the things users normally do with Micro-Manager. Let’s start with the SnapLiveManager that you can obtain using “mm.live()”.

Use the REPL to Snap and Display an image in a single line of code:

images = mm.live().snap(true);

Note that this call returns a list of type “Image”. Image is a datastructure that holds the actual pixel data, but also metadata such as width and height, bytes per pixel, microscope metadata, and “Coords”. Coords specify the position in a multi-dimensional acquisition where the image belongs. Coords need to be created with a “builder”. You can obtain a builder using:

import org.micromanager.data.Coordinates;
cb = Coordinates.builder();

You do need to set all axes of the Coordinates builder, or strange bugs will slip in. Build a Coords with the channel set to position 2, time to 1, z, and position to 0:

coord = cb.c(2).t(1).z(0).p(0).build();

Micro-Manager 2.0 (Java) API

Datastore objects can be thought of as collections of images. They can store images in RAM or on disk (in multiple formats). The DataManager can create Datastores, for instance:

store = mm.data().createRAMDatastore();

To open a viewer displaying the data in your store, use:

viewer = mm.displays().createDisplay(store);

Now write a script that snaps two images without displaying them, inserts them into a datastore, and displays the datastore.

Micro-Manager 2.0 (Java) API

One way to do this:

// import needed to get the Coords builder               
import org.micromanager.data.Coordinates;

store = mm.data().createRAMDatastore();
display = mm.displays().createDisplay(store);
// create the Coords builder, and initialize all axes to zero
cb = Coordinates.builder();
cb.c(0).t(0).p(0).z(0);

for (c = 0; c < 2; c++) {
   // snap an image but do not display
   images = mm.live().snap(false);
   img = images.get(0);
   // copy image with Coords specified by our builder
   cImg = img.copyAtCoords(cb.c(c).build());
   // and place it in the store
   store.putImage(cImg);
}

Micro-Manager 2.0 (Java) API

User feedback

The LogManager (get it using: mm.logs()) interacts with the logging system of Micro-Manager. Logs can be found in the "CoreLogs" directory within the Micro-Manager application directory (for instance: C:\Program Files\Micro-Manager\Corelogs). The LogManager can also be used to show messages to the user. Use the REPL to display a message in the GUI:

mm.logs().showMessage("Hello");

Use the REPL to log an error, and check the logs to see if it is there:

mm.logs().logError("This is not really an error");

Use the ScriptManager to print a message to the REPL:

mm.scripter().message("Insert interesting message here");

Micro-Manager 2.0 (Java) API

Position List

The PositionListManager gives access to the Stage Position List Dialog content. A PositionList contains instances of MultiStagePosition. You can use the static function MultiStagePosition.goToPosition to move the stage(s) to a desired postion. Add a few positions to the Stage Position List in the GUI (use the Stage Control to move to different positions), then write a script to move the stage to the second position in the list:

pl = mm.positions().getPositionList();
msp = pl.getPosition(1);
msp.goToPosition(msp, mmc);

Micro-Manager 2.0 (Java) API

Using image analysis (ImageJ

Pixels can be accessed through the Image object, and used in any image processing/analysis code that is on the classpath. ImageJ is one such library that is readily available (others are imglib2 and boofCV). Convenience functions to convert between Micro-Manager and ImageJ data structures are provided in ImageJConverter, accessible through mm.data().ij().

Write a short script that snaps an image without displaying it, gets an ImageJ ImageProcessor from that image, uses the Imagej function "findEdges()" to find edges, converts it back into a Micro-Manager Image, and displays it using mm.live():

images = mm.live().snap(false);
img = images.get(0);
// convert image into an ImageJ ImageProcessor 
ip = mm.data().ij().createProcessor(img);
ip.findEdges();
// convert ImageProcessor back into a MM Image and display
newImg = mm.data().ij().createImage(ip, img.getCoords(), null);
mm.live().displayImage(newImg);

Micro-Manager 2.0 (Java) API

Dealing with image sequences

Often, streaming the camera is the fastest way to acquire images. Combined with hardware synchronization, very fast multi-D acquisitions are possible. Some special coding strategies are needed to acquire images from an image sequence. Write a script that starts a sequence of 10 images, and puts them as a time series into a data store:

cb = mm.data().getCoordsBuilder().z(0).c(0).p(0).t(0);
store = mm.data().createRAMDatastore();
display = mm.displays().createDisplay(store);
mmc.startSequenceAcquisition(10, 0, true);
int curFrame = 0;
while (mmc.getRemainingImageCount() > 0 || mmc.isSequenceRunning(mmc.getCameraDevice())) {
   if (mmc.getRemainingImageCount() > 0) {
      tagged = mmc.popNextTaggedImage();
      // Convert to an Image at the desired time point
      image = mm.data().convertTaggedImage(tagged, cb.time(curFrame).build(), null);
      store.putImage(image);
      curFrame++;
   }
   else { mmc.sleep(5); }
}

Micro-Manager 2.0 (Java) API

Dealing with image sequences(2)

Now run a sequence of 10 images, and put the odd numbered images into channel 0, and the even numbered ones in channel 1 (resulting in 5 time points total):

cb = mm.data().getCoordsBuilder().z(0).c(0).p(0).t(0);
store = mm.data().createRAMDatastore();
display = mm.displays().createDisplay(store);
mmc.startSequenceAcquisition(10, 0, true);
int curFrame = 0;
while (mmc.getRemainingImageCount() > 0 || mmc.isSequenceRunning(mmc.getCameraDevice())) {
   if (mmc.getRemainingImageCount() > 0) {
      tagged = mmc.popNextTaggedImage();
      // Convert to an Image at the desired channel.
      image = mm.data().convertTaggedImage(tagged, 
                 cb.t(curFrame / 2).c(curFrame % 2).build(), null);
      store.putImage(image);
      curFrame++;
   }
   else { mmc.sleep(5); }
}
					

Micro-Manager 2.0 (Java) API

Acquisitions

The Micro-Manager acquisition engine translates instructions such as those provided through the MDA window into instructions to the hardware, and puts the resulting images into a datastore. You get access to the Acquisition Engine through the AcquisitionManager. Write a one liner to run an acquisition with the current settings in the MDA dialog:

mm.acquisitions().runAcquistion();
// or
mm.acquisitions().runAcquisitionNonBlocking();

Acquisition Settings are contained in the SequenceSettings class. Although these can be changed directly, the preferred (and in the future, only) way to do so is through a "Builder", which you can obtain with:

import org.micromanager.acquisition.SequenceSettings;

sequenceSettings = mm.acquisitions().getAcquisitionSettings();
sb = new SequenceSettings.Builder(sequenceSettings);

Micro-Manager 2.0 (Java) API

Acquisitions

Write a short script that updates the comments in the MDA dialog:

import org.micromanager.acquisition.SequenceSettings;
sequenceSettings = mm.acquisitions().getAcquisitionSettings();
sb = new SequenceSettings.Builder(sequenceSettings);

sb.comment("Where is the Red Necked Phalarope?");
mm.acquisitions().setAcquisitionSettings(sb.build());

A very powerful feature is the addition of "Runnables" to an acquisition. Using the function "attachRunnable()", you can add a Runnable, and specify when (i.e. before which specific image(s) in the acquisition the Runnable should run. Runnables are a concept from the Java world, specifying a piece of code that will "run" when it is called. In Beanshell, you can create a Runnable with the following code:

runnable = new Runnable() {
   public void run() {
      // do stuff here
   }
}

Micro-Manager 2.0 (Java) API

Acquisitions

Write a script that attaches a Runnable to the acquisition. Imagine a non-motorized microscope, and you want to prompt the user to put a new filter cube in place whenever a new channel is imaged:

mm.acquisitions().clearRunnables();

runnable = new Runnable() {
   int count = 0;
   public void run() {
      settings = mm.acquisitions().getAcquisitionSettings();
      channels = settings.channels;
      channel = channels.get(count);	
      mm.logs().showMessage("Move filters for channel " + channel.config + " in place");
      ++count;
      if (count >= channels.size()) {
         count = 0;
      }
   }
};

mm.acquisitions().attachRunnable(-1, 0, -1, 0, runnable);
The End
Overview