import ij.*; import ij.plugin.*; import ij.gui.*; import ij.process.*; /** This plugin does various calculations on two images or stacks. Adapted to operate on the RGB planes independently by G. Landini 17/July/2004 Now colour images can be operated plane by plane. The result of the RGB operations are rounded and trimmed to the 8 bit space in each plane. This is useful to perform background uneven illumination correction in brightfield microscopy using colour images: image/brightfield * 255 Before this plugin returned a greyscale result, now it returns an RGB result. Make sure both images are RGB! */ public class Calculator_Plus implements PlugIn { static String title = "Calculator Plus"; static final int SCALE=0, ADD=1, SUBTRACT=2, MULTIPLY=3, DIVIDE=4; static String[] ops = {"Scale: i2 = i1 x k1 + k2", "Add: i2 = (i1+i2) x k1 + k2", "Subtract: i2 = (i1-i2) x k1 + k2", "Multiply: i2 = (i1*i2) x k1 + k2", "Divide: i2 = (i1/i2) x k1 + k2"}; static int operation = SCALE; static double k1 = 1; static double k2 = 0; static boolean createWindow = true; static boolean rgbPlanes = false; int[] wList; private String[] titles; int i1Index; int i2Index; ImagePlus i1; ImagePlus i2; boolean replicate; public void run(String arg) { if (IJ.versionLessThan("1.27w")) return; wList = WindowManager.getIDList(); if (wList==null || wList.length<2) { IJ.showMessage(title, "There must be at least two windows open"); return; } titles = new String[wList.length]; for (int i=0; i1) { createWindow = true; replicate = true; } return true; } public void calculate(ImagePlus i1, ImagePlus i2, double k1, double k2) { double v1, v2=0, r1, g1, b1, r2, g2, b2; int iv1, iv2, r, g=0, b=0; int width = i1.getWidth(); int height = i1.getHeight(); ImageProcessor ip1, ip2; int slices1 = i1.getStackSize(); int slices2 = i2.getStackSize(); float[] ctable1 = i1.getCalibration().getCTable(); float[] ctable2 = i2.getCalibration().getCTable(); ImageStack stack1 = i1.getStack(); ImageStack stack2 = i2.getStack(); int currentSlice = i2.getCurrentSlice(); for (int n=1; n<=slices2; n++) { ip1 = stack1.getProcessor(n<=slices1?n:slices1); ip2 = stack2.getProcessor(n); ip1.setCalibrationTable(ctable1); ip2.setCalibrationTable(ctable2); if (rgbPlanes == true) { for (int x=0; x>16); g1 = (double) ((iv1 & 0x00ff00)>>8); b1 = (double) ( iv1 & 0x0000ff); r2 = (double) ((iv2 & 0xff0000)>>16); g2 = (double) ((iv2 & 0x00ff00)>>8); b2 = (double) ( iv2 & 0x0000ff); switch (operation) { case SCALE: r2 = r1; g2 = g1; b2 = b1; break; case ADD: r2 += r1; g2 += g1; b2 += b1; break; case SUBTRACT: r2 = r1-r2; g2 = g1-g2; b2 = b1-b2; break; case MULTIPLY: r2 *= r1; g2 *= g1; b2 *= b1; break; case DIVIDE: r2 = r2!=0.0?r1/r2:0.0; g2 = g2!=0.0?g1/g2:0.0; b2 = b2!=0.0?b1/b2:0.0; break; } r2 = r2 * k1 + k2; g2 = g2 * k1 + k2; b2 = b2 * k1 + k2; r = (int) Math.floor((r2>255.0?255:(r2<0.0?0:r2))+.5); g = (int) Math.floor((g2>255.0?255:(g2<0.0?0:g2))+.5); b = (int) Math.floor((b2>255.0?255:(b2<0.0?0:b2))+.5); ip2.putPixel(x, y,((r & 0xff)<<16)+((g & 0xff)<<8)+(b & 0xff)); } } } else{ for (int x=0; x