A Processing sketch plug-in

Processing is a versatile graphics language based on Java. Among other things, it provides a simple interface to process images using GLSL shaders. Here, I provide a simple example of a Processing sketch accessing the memory mapped data stream generated by Scanbox. This particular example simply posterizes the image using pre-defined shaders in Processing. Of course, you can write your own to do rather complex image processing.

To run the example, simply run the Processing sketch alongside Scanbox. Then enable the “plugin” and “focus” checkboxes in Scanbox. The main advantage of this mechanism (over a Matlab plugin) is that it provides an easy interface to do shader processing on the incoming data stream. I am now working on real-time non-rigid image registration, cell segmentation and cell extraction for use in closed-loop experiments.

// A processing plugin for Scanbox

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.ByteOrder;

RandomAccessFile f;    // memory mapped file
MappedByteBuffer o;

PImage theFrame;
int state, nrow, ncol;

void setup() {

  size(796, 512); 

  // establish memory mapped file
  
  try {
    f = new RandomAccessFile("C:\\Users\\dario\\Documents\\MATLAB\\Scanbox_Tower_v1\\mmap\\scanbox.mmap", "rw");
  } 
  catch (IOException e) {
    println(e);
  }

  try {
    o = f.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 16+800*800*4);
    o.order(ByteOrder.LITTLE_ENDIAN);
  } 
  catch (IOException e) {
    println(e);
  }   

  textSize(24);
  fill(200,200,200);
  
  frameRate(60);
  background(0);
}

void draw() {

  int state = o.getShort(0);

  switch(state) {

  case -1:
    break;

  case -2:
    break;

  default: // frame available
    
    getFrame();                     // get a frame from the scope
    image(theFrame, 0, 0);          // consume it 
    filter(POSTERIZE,4);            // do something with the data here
    o.putShort(0, (short) -1);      // signal Scanbox that frame has been consumed
    text(state,20,40);  // display frame number
  }
}

public void getFrame() {

  int v0, v1;
  byte val0, val1;
  int i, j, k, m;

  state = o.getShort(0);
  nrow = o.getShort(2);
  ncol = o.getShort(4);

  theFrame = createImage(ncol, nrow, RGB);
  theFrame.loadPixels();
  m = 0;
  for (i=0; i<nrow; i++) 
    for (j=0; j<ncol; j++) {
      k = j*nrow+i; 
      try {
        v0 = o.getShort(16+2*k); 
        v1 = o.getShort(16+2*k+2*nrow*ncol);
        v0 = (v0<0)?v0:(v0+32768);
        v1 = (v1<0)?v1:(v1+32768);
        val0 = (byte) map(v0, 0, 65535, 255, 0);
        val1 = (byte) map(v1, 0, 65535, 255, 0);
        theFrame.pixels[m++] = color(val1, val0, 0);
      } 
      catch (Exception e) {
        println(e);
      }
    }
  theFrame.updatePixels();
}

The picture above shows Scanbox running in parallel with the Processing sketch (overlapping on the right). The image on the right is quantized to contain only 4 different values. As the original image has 16 bits, this represents a compression factor of 16k. Not bad.