| RGBStackMerge |

    package ij.plugin;
    import ij.*;
    import ij.process.*;
    import ij.gui.*;

    public class RGBStackMerge implements PlugIn {

        private ImagePlus imp;
        private byte[] blank;

        /** Merges one, two or three 8-bit or RGB stacks into a single RGB stack. */
        public void run(String arg) {
            imp = WindowManager.getCurrentImage();
            mergeStacks();
        }

        /** Combines three grayscale stacks into one RGB stack. */
        public void mergeStacks() {
            int[] wList = WindowManager.getIDList();
            if (wList==null) {
                IJ.error("No images are open.");
                return;
            }

            String[] titles = new String[wList.length+1];
            for (int i=0; i<wList.length; i++) {
                ImagePlus imp = WindowManager.getImage(wList[i]);
                titles[i] = imp!=null?imp.getTitle():"";
            }
            String none = "*None*";
            titles[wList.length] = none;

            GenericDialog gd = new GenericDialog("RGB Merge");
            gd.addChoice("Red:", titles, titles[0]);
            gd.addChoice("Green:", titles, titles[1]);
            String title3 = titles.length>2?titles[2]:none;
            gd.addChoice("Blue:", titles, title3);
            gd.addCheckbox("Keep source images", false);
            gd.showDialog();
            if (gd.wasCanceled())
                return;
            int[] index = new int[3];
            index[0] = gd.getNextChoiceIndex();
            index[1] = gd.getNextChoiceIndex();
            index[2] = gd.getNextChoiceIndex();
            boolean keep = gd.getNextBoolean();

            ImagePlus[] image = new ImagePlus[3];
            int stackSize = 0;
            int width = 0;
            int height = 0;
            for (int i=0; i<3; i++) {
                if (index[i]<wList.length) {
                    image[i] = WindowManager.getImage(wList[index[i]]);
                    width = image[i].getWidth();
                    height = image[i].getHeight();
                    stackSize = image[i].getStackSize();
                }
            }
            if (width==0) {
                IJ.error("There must be at least one source image or stack.");
                return;
            }
            for (int i=0; i<3; i++) {
                ImagePlus img = image[i];
                if (img!=null) {
                    if (img.getStackSize()!=stackSize) {
                        IJ.error("The source stacks must all have the same number of slices.");
                        return;
                    }
                    //if (!(img.getType()==ImagePlus.GRAY8||img.getType()==ImagePlus.COLOR_RGB)) {
                    //    IJ.error("The source stacks must be 8-bit grayscale or RGB.");
                    //    return;
                    //}
                    if (img.getWidth()!=width || image[i].getHeight()!=height) {
                        IJ.error("The source images or stacks must have the same width and height.");
                        return;
                    }
                }
            }

            ImageStack red = image[0]!=null?image[0].getStack():null;
            ImageStack green = image[1]!=null?image[1].getStack():null;
            ImageStack blue = image[2]!=null?image[2].getStack():null;
            ImageStack rgb = mergeStacks(width, height, stackSize, red, green, blue, keep);
            if (!keep)
                for (int i=0; i<3; i++) {
                    if (image[i]!=null) {
                        image[i].changes = false;
                        image[i].close();
                    }
                }
            ImagePlus imp2 = new ImagePlus("RGB", rgb);
            if (image[0]!=null)
                imp2.setCalibration(image[0].getCalibration());
            imp2.show();
        }

        public ImageStack mergeStacks(int w, int h, int d, ImageStack red, ImageStack green, ImageStack blue, boolean keep) {
            ImageStack rgb = new ImageStack(w, h);
            int inc = d/10;
            if (inc<1) inc = 1;
            ColorProcessor cp;
            int slice = 1;
            blank = new byte[w*h];
            byte[] redPixels, greenPixels, bluePixels;
            boolean invertedRed = red!=null?red.getProcessor(1).isInvertedLut():false;
            boolean invertedGreen = green!=null?green.getProcessor(1).isInvertedLut():false;
            boolean invertedBlue = blue!=null?blue.getProcessor(1).isInvertedLut():false;
            try {
                for (int i=1; i<=d; i++) {
                    cp = new ColorProcessor(w, h);
                    redPixels = getPixels(red, slice, 0);
                    greenPixels = getPixels(green, slice, 1);
                    bluePixels = getPixels(blue, slice, 2);
                    if (invertedRed) redPixels = invert(redPixels);
                    if (invertedGreen) greenPixels = invert(greenPixels);
                    if (invertedBlue) bluePixels = invert(bluePixels);
                    cp.setRGB(redPixels, greenPixels, bluePixels);
                if (keep) {
                    slice++;
                } else {
                        if (red!=null) red.deleteSlice(1);
                    if (green!=null &&green!=red) green.deleteSlice(1);
                    if (blue!=null&&blue!=red && blue!=green) blue.deleteSlice(1);
                }
                rgb.addSlice(null, cp);
                if ((i%inc) == 0) IJ.showProgress((double)i/d);
                }
            IJ.showProgress(1.0);
            } catch(OutOfMemoryError o) {
                IJ.outOfMemory("Merge Stacks");
                IJ.showProgress(1.0);
            }
            return rgb;
        }

         byte[] getPixels(ImageStack stack, int slice, int color) {
             if (stack==null)
                return blank;
            Object pixels = stack.getPixels(slice);
            if (!(pixels instanceof int[])) {
                if (pixels instanceof byte[])
                    return (byte[])pixels;
                else {
                    ImageProcessor ip = stack.getProcessor(slice);
                    ip = ip.convertToByte(true);
                    return (byte[])ip.getPixels();
                }
            } else { //RGB
                byte[] r,g,b;
                int size = stack.getWidth()*stack.getHeight();
                r = new byte[size];
                g = new byte[size];
                b = new byte[size];
                ColorProcessor cp = (ColorProcessor)stack.getProcessor(slice);
                cp.getRGB(r, g, b);
                switch (color) {
                    case 0: return r;
                    case 1: return g;
                    case 2: return b;
                }
            }
            return null;
        }

        byte[] invert(byte[] pixels) {
            byte[] pixels2 = new byte[pixels.length];
            System.arraycopy(pixels, 0, pixels2, 0, pixels.length);
            for (int i=0; i<pixels2.length; i++)
                pixels2[i] = (byte)(255-pixels2[i]&255);
            return pixels2;
        }

    }

| RGBStackMerge |