import ij.*; import ij.plugin.filter.PlugInFilter; import ij.process.*; import ij.gui.*; import java.awt.event.*; // This plugin enables us to view each channel of RGB stacks to animate separately // without actually processing the stack. // The 'byte viewer' is the essential key window which only accepts the key commands and B&C, // and should always be re-activated before any action. // The entire plugin mode will be quitted by pressing 'Esc' key or closing the 'byte viewer' window // (not by closing the original stack). public class RGB_Stack_Browser implements PlugInFilter, KeyListener { ImagePlus imp; ImagePlus rgb_im; ImagePlus byte_im; ColorProcessor cp; ImageProcessor rgb_ip; ImageProcessor byte_ip; int[] pixels; int[] rgb_pixels; byte[] byte_pixels; ImageWindow rgb_window; ImageWindow byte_window; ImageCanvas rgb_canvas; ImageCanvas byte_canvas; ImageStack rgbStack; int w, h ; int n, nSlices; boolean startanimation = true; double animationSpeed = 8.0; // frames per second char keyChar='r'; int keyCode=0; char channel = 'r'; public int setup(String arg, ImagePlus imp) { this.imp = imp; return DOES_RGB+NO_CHANGES; } public void run(ImageProcessor ip) { w = imp.getWidth(); h = imp.getHeight(); rgbStack = imp.getStack(); nSlices = rgbStack.getSize(); rgb_im = NewImage.createRGBImage ("RGB Viewer", w, h, 1, NewImage.FILL_BLACK); rgb_ip = rgb_im.getProcessor(); rgb_pixels = (int[]) rgb_ip.getPixels(); byte_im = NewImage.createByteImage ("Byte Viewer", w, h, 1, NewImage.FILL_BLACK); byte_ip = byte_im.getProcessor(); byte_pixels = (byte[]) byte_ip.getPixels(); rgb_im.show(); rgb_window = rgb_im.getWindow(); rgb_canvas = rgb_window.getCanvas(); byte_im.show(); byte_window = byte_im.getWindow(); byte_canvas = byte_window.getCanvas(); rgb_canvas.addKeyListener(this); byte_canvas.addKeyListener(this); // The 'byte viewer' window should be activated to receive the key command. rGBAnimation(imp); showExit(); } public void rGBAnimation(ImagePlus imp){ long time, nextTime=System.currentTimeMillis(); n=1; while (true) { while (startanimation == true ) { if (keyCode==27) {return;} //The process will terminate with 'Esc' key. else if (byte_window.isClosed()){return;} //The process will terminate when the 'byte viewer' is closed. else if (keyChar=='=') { startanimation = false; break; } else if ((keyChar >= '0') && (keyChar <= '9')) { //determining the animation speed animationSpeed =(double)(Math.pow(2, ((int)keyChar-48) ))/4.0; } peekSlice(); time = System.currentTimeMillis(); if (time=nSlices) n=1; else n++; } IJ.wait(80); if (keyCode==27) {return;} else if (byte_window.isClosed()){return;} if (keyCode==KeyEvent.VK_RIGHT) { //go to next slice pressing 'right' key (key# 39) if (++n>=nSlices) n=nSlices; } else if (keyCode==KeyEvent.VK_LEFT) { //back to previous slice by pressing 'left' key (key# 37) if (--n<=1) n=1; } else if (keyChar=='j') { n=(int)IJ.getNumber("Enter # to jump", ((double)n)); // specify the slice # to jump. } else if (keyChar==' ') { //Animation restarts with space key. startanimation = true; } peekSlice(); } } public void peekSlice() { int[] table = new int[256]; // for the RGB viewer to reflect the B&C value of the byte viewer int min = (int)byte_ip.getMin(); int max = (int)byte_ip.getMax(); for (int val=0; val<256; val++) { if (val<=min) table[val] = 0; else if (val>=max) table[val] = 255; else table[val] = (int)(((double)(val-min)/(max-min))*255); } cp = (ColorProcessor)rgbStack.getProcessor(n); pixels = (int[]) cp.getPixels(); for (int i=0; i>16); int green = (int)((pixels[pos]&0x00ff00)>>8); int blue = (int)(pixels[pos]&0x0000ff); if (channel=='r'){ byte_pixels[pos] = (byte) red; red = table[red]; } else if (channel=='g'){ byte_pixels[pos] = (byte) green; green = table[green]; } else if (channel=='b'){ byte_pixels[pos] = (byte) blue; blue = table [blue]; } rgb_pixels[pos] = ((red&0xff)<<16)+((green&0xff)<<8)+(blue&0xff); } } byte_im.updateAndDraw(); rgb_im.updateAndDraw(); IJ.showStatus("Channel="+channel+"; "+animationSpeed+"frames/s; Slice #= "+n+"/"+nSlices); } public void keyPressed(KeyEvent e) { keyCode = e.getKeyCode(); keyChar = e.getKeyChar(); if (keyChar=='r'){ channel = 'r'; } else if (keyChar=='g'){ channel = 'g'; } else if (keyChar=='b'){ channel = 'b'; } } public void keyReleased(KeyEvent e) { keyChar = 0; keyCode = 0; } public void keyTyped(KeyEvent e) { } void showExit() { IJ.showMessage("Browser mode ended normally."); } }