ImageMath.java :  » Image » objectj » ij » plugin » filter » Java Open Source

Java Open Source » Image » objectj 
objectj » ij » plugin » filter » ImageMath.java
package ij.plugin.filter;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.macro.*;
import java.awt.*;

/** This plugin implements ImageJ's Process/Math submenu. */
public class ImageMath implements ExtendedPlugInFilter, DialogListener {
  
  public static final String MACRO_KEY = "math.macro";
  private int flags = DOES_ALL|SUPPORTS_MASKING|KEEP_PREVIEW;
  private String arg;
  private ImagePlus imp;
  private boolean canceled;  
  private double lower=-1.0, upper=-1.0;
  
  private static double addValue = 25;
  private static double mulValue = 1.25;
  private static double minValue = 0;
  private static double maxValue = 255;
  private static final String defaultAndValue = "11110000";
  private static String andValue = defaultAndValue;
  private static final double defaultGammaValue = 0.5;
  private static double gammaValue = defaultGammaValue;
  private static String macro = Prefs.get(MACRO_KEY, "v=v+50*sin(d/10)");
  private int w, h, w2, h2;
  private boolean hasX, hasA, hasD, hasGetPixel;
  private String macro2;
  private PlugInFilterRunner pfr;
  private GenericDialog gd;

  public int setup(String arg, ImagePlus imp) {
    this.arg = arg;
    this.imp = imp;
    IJ.register(ImageMath.class);
    if (imp!=null && imp.getStackSize()==1 && arg.equals("macro"))
      flags |= PARALLELIZE_IMAGES;
    else
      flags |= PARALLELIZE_STACKS;
    return flags;
  }

  public void run(ImageProcessor ip) {
     if (canceled)
       return;
     
     if (arg.equals("add")) {
      ip.add(addValue);
      return;
    }

     if (arg.equals("sub")) {
      ip.subtract(addValue);
      return;
    }

     if (arg.equals("mul")) {
      ip.multiply(mulValue);
      return;
    }

     if (arg.equals("div")) {
       if (mulValue==0.0&&imp.getBitDepth()!=32)
         return;
      ip.multiply(1.0/mulValue);
      return;
    }

     if (arg.equals("and")) {
       try {
        ip.and(Integer.parseInt(andValue,2));
      } catch (NumberFormatException e) {
        andValue = defaultAndValue;
        IJ.error("Binary number required");
      }
      return;
    }

     if (arg.equals("or")) {
       try {
        ip.or(Integer.parseInt(andValue,2));
      } catch (NumberFormatException e) {
        andValue = defaultAndValue;
        IJ.error("Binary number required");
      }
      return;
    }
      
     if (arg.equals("xor")) {
       try {
        ip.xor(Integer.parseInt(andValue,2));
      } catch (NumberFormatException e) {
        andValue = defaultAndValue;
        IJ.error("Binary number required");
      }
      return;
    }
    
     if (arg.equals("min")) {
       ip.min(minValue);
      if (!(ip instanceof ByteProcessor))
        ip.resetMinAndMax();
      return;
    }

     if (arg.equals("max")) {
       ip.max(maxValue);
      if (!(ip instanceof ByteProcessor))
        ip.resetMinAndMax();
      return;
    }

     if (arg.equals("gamma")) {
       if ((gammaValue<0.1 || gammaValue>5.0) && !previewing()) {
         IJ.error("Gamma must be between 0.1 and 5.0");
         gammaValue = defaultGammaValue;
         return;
       }
      ip.gamma(gammaValue);
      return;
    }

     if (arg.equals("set")) {
       boolean rgb = ip instanceof ColorProcessor;
      if (rgb) {
        if (addValue>255.0) addValue=255.0;
        if (addValue<0.0) addValue=0.0;
        int ival = (int)addValue;
         ip.setValue(ival + (ival<<8) + (ival<<16));
      } else
         ip.setValue(addValue);
      ip.fill();
      return;
    }

     if (arg.equals("log")) {
      ip.log();
      return;
    }
    
     if (arg.equals("exp")) {
      ip.exp();
      return;
    }

     if (arg.equals("sqr")) {
      ip.sqr();
      return;
    }

     if (arg.equals("sqrt")) {
      ip.sqrt();
      return;
    }

     if (arg.equals("reciprocal")) {
      if (!isFloat(ip)) return;
      float[] pixels = (float[])ip.getPixels();
      for (int i=0; i<ip.getWidth()*ip.getHeight(); i++) {
        if (pixels[i]==0f)
          pixels[i] = Float.NaN;
        else
          pixels[i] = 1f/pixels[i];
      }
      ip.resetMinAndMax();
      return;
    }
    
     if (arg.equals("nan")) {
       setBackgroundToNaN(ip);
      return;
    }

     if (arg.equals("abs")) {
      if (!((ip instanceof FloatProcessor)||imp.getCalibration().isSigned16Bit())) {
        IJ.error("32-bit or signed 16-bit image required");
        canceled = true;
      } else {
        ip.abs();
        ip.resetMinAndMax();
      }
      return;
    }

     if (arg.equals("macro")) {
      applyMacro(ip);
      return;
    }

  }
  
  boolean previewing() {
    return gd!=null && gd.getPreviewCheckbox().getState();
  }
 
   boolean isFloat(ImageProcessor ip) {
    if (!(ip instanceof FloatProcessor)) {
      IJ.error("32-bit float image required");
      canceled = true;
      return false;
    } else
      return true;
  }
  
  void getValue (String title, String prompt, double defaultValue, int digits) {
    int places = Analyzer.getPrecision();
    if (digits>0 || (int)defaultValue!=defaultValue)
      digits = Math.max(places, 1);
    gd = new GenericDialog(title);
    gd.addNumericField(prompt, defaultValue, digits, 8, null);
    gd.addPreviewCheckbox(pfr);
    gd.addDialogListener(this);
    gd.showDialog();
  }

  void getBinaryValue (String title, String prompt, String defaultValue) {
    gd = new GenericDialog(title);
    gd.addStringField(prompt, defaultValue);
    gd.addPreviewCheckbox(pfr);
    gd.addDialogListener(this);
    gd.showDialog();
  }

  void getGammaValue (double defaultValue) {
    gd = new GenericDialog("Gamma");
    gd.addSlider("Value:", 0.05, 5.0, defaultValue);
    gd.addPreviewCheckbox(pfr);
    gd.addDialogListener(this);
    gd.showDialog();
  }

  /** Set non-thresholded pixels in a float image to NaN. */
  void setBackgroundToNaN(ImageProcessor ip) {
    if (lower==-1.0 && upper==-1.0) {
      lower = ip.getMinThreshold();
      upper = ip.getMaxThreshold();
      if (lower==ImageProcessor.NO_THRESHOLD || !(ip instanceof FloatProcessor)) {
        IJ.error("Thresholded 32-bit float image required");
        canceled = true;
        return;
      }
    }
        float[] pixels = (float[])ip.getPixels();
        int width = ip.getWidth();
        int height = ip.getHeight();
        double v;
        for (int y=0; y<height; y++) {
            for (int x=0; x<width; x++) {
                  v = pixels[y*width+x];
                  if (v<lower || v>upper)
                      pixels[y*width+x] = Float.NaN;
            }
        }
    ip.resetMinAndMax();
    return;
  }
  
  // first default: v = v+(sin(x/(w/25))+sin(y/(h/25)))*40
  // a=round(a/10); if (a%2==0) v=0;
  // cone: v=d
  // translate: v=getPixel(x+10,y+10)
  // flip vertically: v=getPixel(x,h-y-1)
  // spiral: v=(sin(d/10+a*PI/180)+1)*128
  // spiral on image: v=v+50*sin(a*PI/180+d/5)
  // spiral rotation: a+=PI+d*PI/360; v=getPixel(d*cos(a)+w/2,d*sin(a)+h/2);
  // v=sin(log(d)*8 + a) * sin(a*8)
  // v=(a * 40.74 + d) % 32
  // v=floor((a * 40.75 + 1) % 2)
  // v=sin(x) * sin(y)
  // v=cos(0.2*x) + sin(0.2*y)

  void applyMacro(ImageProcessor ip) {
    int PCStart = 23;
    if (macro2==null) return;
    if (macro2.indexOf("=")==-1) {
      IJ.error("The variable 'v' must be assigned a value (e.g., \"v=255-v\")");
      canceled = true;
      return;
    }
    macro = macro2;
    Program pgm = (new Tokenizer()).tokenize(macro);
    hasX = pgm.hasWord("x");
    hasA = pgm.hasWord("a");
    hasD = pgm.hasWord("d");
    hasGetPixel = pgm.hasWord("getPixel");
    w = imp.getWidth();
    h = imp.getHeight();
    w2 = w/2;
    h2 = h/2;
    String code =
      "var v,x,y,z,w,h,d,a;\n"+
      "function dummy() {}\n"+
      macro2+";\n"; // code starts at program counter location 'PCStart'
    Interpreter interp = new Interpreter();
    interp.run(code, null);
    if (interp.wasError())
      return;
    Prefs.set(MACRO_KEY, macro);
    interp.setVariable("w", w);
    interp.setVariable("h", h);
    boolean showProgress = pfr.getSliceNumber()==1 && !Interpreter.isBatchMode();
    interp.setVariable("z", pfr.getSliceNumber()-1);
    int bitDepth = imp.getBitDepth();
    Rectangle r = ip.getRoi();
    int inc = r.height/50;
    if (inc<1) inc = 1;
    double v;
    int index, v2;
    if (bitDepth==8) {
      byte[] pixels1 = (byte[])ip.getPixels();
      byte[] pixels2 = pixels1;
      if (hasGetPixel)
        pixels2 = new byte[w*h];
      for (int y=r.y; y<(r.y+r.height); y++) {
        if (showProgress && y%inc==0)
          IJ.showProgress(y-r.y, r.height);
        interp.setVariable("y", y);
        for (int x=r.x; x<(r.x+r.width); x++) {
          index = y*w+x;
          v = pixels1[index]&255;
          interp.setVariable("v", v);
          if (hasX) interp.setVariable("x", x);
          if (hasA) interp.setVariable("a", getA(x,y));
          if (hasD) interp.setVariable("d", getD(x,y));
          interp.run(PCStart);
          v2 = (int)interp.getVariable("v");
          if (v2<0) v2 = 0;
          if (v2>255) v2 = 255;
          pixels2[index] = (byte)v2;
        }
      }
      if (hasGetPixel) System.arraycopy(pixels2, 0, pixels1, 0, w*h);
    } else if (bitDepth==24) {
      int rgb, red, green, blue;
      int[] pixels1 = (int[])ip.getPixels();
      int[] pixels2 = pixels1;
      if (hasGetPixel)
        pixels2 = new int[w*h];
      for (int y=r.y; y<(r.y+r.height); y++) {
        if (showProgress && y%inc==0)
          IJ.showProgress(y-r.y, r.height);
        interp.setVariable("y", y);
        for (int x=r.x; x<(r.x+r.width); x++) {
          if (hasX) interp.setVariable("x", x);
          if (hasA) interp.setVariable("a", getA(x,y));
          if (hasD) interp.setVariable("d", getD(x,y));
          index = y*w+x;
          rgb = pixels1[index];
          if (hasGetPixel) {
            interp.setVariable("v", rgb);
            interp.run(PCStart);
            rgb = (int)interp.getVariable("v");
          } else {
            red = (rgb&0xff0000)>>16;
            green = (rgb&0xff00)>>8;
            blue = rgb&0xff;
            interp.setVariable("v", red);
            interp.run(PCStart);
            red = (int)interp.getVariable("v");
            if (red<0) red=0; if (red>255) red=255;
            interp.setVariable("v", green);
            interp.run(PCStart);
            green= (int)interp.getVariable("v");
            if (green<0) green=0; if (green>255) green=255;
            interp.setVariable("v", blue);
            interp.run(PCStart);
            blue = (int)interp.getVariable("v");
            if (blue<0) blue=0; if (blue>255) blue=255;
            rgb = 0xff000000 | ((red&0xff)<<16) | ((green&0xff)<<8) | blue&0xff;
          }
          pixels2[index] = rgb;
        }
      }
      if (hasGetPixel) System.arraycopy(pixels2, 0, pixels1, 0, w*h);
    } else {
      for (int y=r.y; y<(r.y+r.height); y++) {
        if (showProgress && y%inc==0)
          IJ.showProgress(y-r.y, r.height);
        interp.setVariable("y", y);
        for (int x=r.x; x<(r.x+r.width); x++) {
          v = ip.getPixelValue(x, y);
          interp.setVariable("v", v);
          if (hasX) interp.setVariable("x", x);
          if (hasA) interp.setVariable("a", getA(x,y));
          if (hasD) interp.setVariable("d", getD(x,y));
          interp.run(PCStart);
          ip.putPixelValue(x, y, interp.getVariable("v"));
        }
      }
    }
    if (showProgress)
      IJ.showProgress(1.0);
    if (pfr.getSliceNumber()==1)
      ip.resetMinAndMax();
  }
  
  final double getD(int x, int y) {
          double dx = x - w2; 
          double dy = y - h2;
          return Math.sqrt(dx*dx + dy*dy);
  }
  
  final double getA(int x, int y) {
    double angle = Math.atan2((h-y-1)-h2, x-w2);
    if (angle<0) angle += 2*Math.PI;
    return angle;
  }

  void getMacro(String macro) {
    gd = new GenericDialog("Expression Evaluator");
    gd.addStringField("Code:", macro, 42);
    gd.setInsets(0,40,0);
    gd.addMessage("v=pixel value, x,y&z=pixel coordinates, w=image width,\nh=image height, a=angle, d=distance from center\n");
    gd.setInsets(5,40,0);
    gd.addPreviewCheckbox(pfr);
    gd.addDialogListener(this);
    gd.addHelp(IJ.URL+"/docs/menus/process.html#math-macro");
    gd.showDialog();
  }

    public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
    this.pfr = pfr;
     if (arg.equals("macro"))
      getMacro(macro);
      else if (arg.equals("add"))
       getValue("Add", "Value: ", addValue, 0);
     else if (arg.equals("sub"))
       getValue("Subtract", "Value: ", addValue, 0);
     else if (arg.equals("mul"))
       getValue("Multiply", "Value: ", mulValue, 2);
     else if (arg.equals("div"))
       getValue("Divide", "Value: ", mulValue, 2);
     else if (arg.equals("and"))
       getBinaryValue("AND", "Value (binary): ", andValue);
     else if (arg.equals("or"))
       getBinaryValue("OR", "Value (binary): ", andValue);
     else if (arg.equals("xor"))
       getBinaryValue("XOR", "Value (binary): ", andValue);
     else if (arg.equals("min"))
       getValue("Min", "Value: ", minValue, 0);
     else if (arg.equals("max"))
       getValue("Max", "Value: ", maxValue, 0);
     else if (arg.equals("gamma"))
       getGammaValue(gammaValue);
     else if (arg.equals("set")) {
       boolean rgb = imp.getBitDepth()==24;
       String prompt = rgb?"Value (0-255): ":"Value: ";
       getValue("Set", prompt, addValue, 0);
    }
    if (gd!=null && gd.wasCanceled())
      return DONE;
    else
      return IJ.setupDialog(imp, flags);
   }

  public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
     if (arg.equals("macro")) {
       String str = gd.getNextString();
      if (previewing() && macro2!=null && !str.equals(macro2))
        gd.getPreviewCheckbox().setState(false);
      macro2 = str;
      } else if (arg.equals("add")||arg.equals("sub")||arg.equals("set"))
      addValue = gd.getNextNumber();
     else if (arg.equals("mul")||arg.equals("div"))
       mulValue = gd.getNextNumber();
     else if (arg.equals("and")||arg.equals("or")||arg.equals("xor"))
       andValue = gd.getNextString();
     else if (arg.equals("min"))
       minValue = gd.getNextNumber();
     else if (arg.equals("max"))
       maxValue = gd.getNextNumber();
     else if (arg.equals("gamma"))
       gammaValue = gd.getNextNumber();
    canceled = gd.invalidNumber();
    if (gd.wasOKed() && canceled) {
      IJ.error("Value is invalid.");
      return false;
    }
    return true;
  }

  public void setNPasses(int nPasses) {
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.