| ImageMath |

    package ij.plugin.filter;
    import ij.*;
    import ij.gui.*;
    import ij.process.*;
    import java.awt.*;

    /** This plugin implements ImageJ's Process/Math submenu. */
    public class ImageMath implements PlugInFilter {

        private String arg;
        private ImagePlus imp;
        private boolean canceled;
        private boolean first; // first stack slice?
        private double lower;
        private double upper;

        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;

        public int setup(String arg, ImagePlus imp) {
            this.arg = arg;
            this.imp = imp;
            first = true;
            IJ.register(ImageMath.class);
            return IJ.setupDialog(imp, DOES_ALL+SUPPORTS_MASKING);
        }

        public void run(ImageProcessor ip) {

            double value;

            if (canceled)
                return;

            if (arg.equals("add")) {
                if (first) addValue = getValue("Add", "Value: ", addValue, 0);
                if (canceled) return;
                ip.add(addValue);
                return;
            }

            if (arg.equals("sub")) {
                if (first) addValue = getValue("Subtract", "Value: ", addValue, 0);
                if (canceled) return;
                ip.add(-addValue);
                return;
            }

            if (arg.equals("mul")) {
                if (first) mulValue = getValue("Multiply", "Value: ", mulValue, 2);
                if (canceled) return;
                ip.multiply(mulValue);
                return;
            }

            if (arg.equals("div")) {
                if (first) mulValue = getValue("Divide", "Value: ", mulValue, 2);
                if (canceled) return;
                if (mulValue!=0.0) ip.multiply(1.0/mulValue);
                return;
            }

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

            if (arg.equals("or")) {
                if (first) andValue = getBinaryValue("OR", "Value (binary): ", andValue);
                if (canceled) return;
                try {
                    ip.or(Integer.parseInt(andValue,2));
                } catch (NumberFormatException e) {
                    andValue = defaultAndValue;
                    IJ.error("Binary number required");
                }
                return;
            }

            if (arg.equals("xor")) {
                if (first) andValue = getBinaryValue("XOR", "Value (binary): ", andValue);
                if (canceled) return;
                try {
                    ip.xor(Integer.parseInt(andValue,2));
                } catch (NumberFormatException e) {
                    andValue = defaultAndValue;
                    IJ.error("Binary number required");
                }
                return;
            }

            if (arg.equals("min")) {
                if (first) minValue = getValue("Min", "Value: ", minValue, 0);
                if (canceled) return;
                ip.min(minValue);
                if (!(ip instanceof ByteProcessor))
                    ip.resetMinAndMax();
                return;
            }

            if (arg.equals("max")) {
                if (first) maxValue = getValue("Max", "Value: ", maxValue, 0);
                if (canceled) return;
                ip.max(maxValue);
                if (!(ip instanceof ByteProcessor))
                    ip.resetMinAndMax();
                return;
            }

            if (arg.equals("gamma")) {
                if (first) gammaValue = getValue("Gamma", "Value (0.1-5.0): ", gammaValue, 2);
                if (canceled) return;
                if (gammaValue<0.1 || gammaValue>5.0) {
                    IJ.error("Gamma must be between 0.1 and 5.0");
                    gammaValue = defaultGammaValue;
                    return;
                }
                ip.gamma(gammaValue);
                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;
            }

        }

        boolean isFloat(ImageProcessor ip) {
            if (!(ip instanceof FloatProcessor)) {
                IJ.error("32-bit float image required");
                canceled = true;
                return false;
            } else
                return true;
        }

        double getValue (String title, String prompt, double defaultValue, int digits) {
                int places = Analyzer.getPrecision();
                if (digits>0 || (int)defaultValue!=defaultValue)
                    digits = Math.max(places, 1);
                GenericDialog gd = new GenericDialog(title);
                gd.addNumericField(prompt, defaultValue, digits, 8, null);
                gd.showDialog();
                if (first) imp.startTiming();
                first = false;
                canceled = gd.wasCanceled();
                if (canceled)
                    return defaultValue;
                return gd.getNextNumber();
        }

        String getBinaryValue (String title, String prompt, String defaultValue) {
                GenericDialog gd = new GenericDialog(title);
                gd.addStringField(prompt, defaultValue);
                gd.showDialog();
                if (first) imp.startTiming();
                first = false;
                canceled = gd.wasCanceled();
                if (canceled)
                    return defaultValue;
                return gd.getNextString();
        }

        /** Set non-thresholded pixels in a float image to NaN. */
        void setBackgroundToNaN(ImageProcessor ip) {
            if (first) {
                lower = ip.getMinThreshold();
                upper = ip.getMaxThreshold();
                first = false;
                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;
        }

    }

| ImageMath |