PS : ImageJ : Register
 
I don't really remember how this works anymore. Documentation is unlikely to occur. Here's the code though. It did work.

Align_Stack.java:

import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.plugin.*;
import ij.process.*;
import ij.gui.*;
import java.awt.event.*;
import java.io.*;
import java.awt.Color;

/**
 * This plugin implements the KeyListener interface and listens
 * for key events generated by the current image.
 */
public class Align_Stack implements PlugIn, KeyListener {
    ImagePlus img;
    ImageProcessor flatProcessor;
    ImagePlus flatImg;
    ImageStack stack;
    String fileName;
    int[] flatdisplacementX;
    int[] flatdisplacementY;
    int[] flatrotation;
    int depth;
    int currentSlice;
    int stepSize;
    
    
    
    
    void reConstruct() {
        flatProcessor.multiply(0);
        for(int z = 1; z<=depth; z++){
            ImageProcessor tempIp = stack.getProcessor(z).duplicate();
            if (z == currentSlice) {
                tempIp.multiply(.5);
            } else if (Math.abs(z-currentSlice)<3){
                tempIp.multiply(.1);
            } else {
                tempIp.multiply(.1/(depth-5));
            }
            flatProcessor.copyBits(tempIp,flatdisplacementX[z],flatdisplacementY[z],Blitter.ADD);
        }
        flatImg.updateAndDraw();
        IJ.log("Slice: "+currentSlice);
    }
    
    void loadData() {
        try {
            if (!( new File(fileName).exists() )) {IJ.error("No input file");return;}
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            for(int i=1;i<=depth;i++) {
                String[] line = br.readLine().split(",");
                flatdisplacementX[i]= new Integer(line[0]).intValue();
                flatdisplacementY[i]= new Integer(line[1]).intValue();
                flatrotation[i]= new Integer(line[2]).intValue();
                stack.getProcessor(i).insert(img.getStack().getProcessor(i),0,0);
                stack.getProcessor(i).rotate(flatrotation[i]);
            }
            br.close();
            reConstruct();
            return;
        } catch (IOException e) {
            IJ.showMessage("FileIO Error On Load: ", ""+e);
            return;
        }
        
    }
    
    void saveData() {
        try {
            new File(fileName).delete();
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
            for(int i=1;i<=depth;i++) {
                pw.print(flatdisplacementX[i]+","+flatdisplacementY[i]+","+flatrotation[i]+"\n");
            }
            pw.flush();
            pw.close();
        } catch (IOException e) {
            IJ.showMessage("FileIO Error On Write: ", ""+e);
            return;
        }
    }
    
    public void run(String arg) {
        img = WindowManager.getCurrentImage();
        ImageWindow win = img.getWindow();
        ImageCanvas canvas = win.getCanvas();
        canvas.addKeyListener(this);
        
        
        
        IJ.write(img.toString());
        //fileName = "/Users/peter/Pictures/registerdata";
        
        fileName = img.getOriginalFileInfo().directory+img.getOriginalFileInfo().fileName+".stackAlignData";
        
        depth = img.getStackSize();
        stack = new ImageStack(img.getWidth(),img.getHeight());
        for (int i = 1;i<=depth;i++) {
            stack.addSlice(null,img.getStack().getProcessor(i).duplicate());
            stack.getProcessor(i).invertLut();
        }
        flatdisplacementX = new int[depth+1];
        flatdisplacementY = new int[depth+1];
        flatrotation = new int[depth+1];
        flatProcessor = img.getStack().getProcessor(1).duplicate();
        currentSlice = 1;
        flatImg = new ImagePlus("Projection", flatProcessor);
        ImageCanvas flatCanvas = new ImageCanvas(flatImg);
        reConstruct();
        new ImageWindow(flatImg, flatCanvas);
        
        
    }
    
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        char keyChar = e.getKeyChar();
        int flags = e.getModifiers();
        IJ.log("keyCode=" + keyCode + " (" + KeyEvent.getKeyText(keyCode)
        + ") keyChar=\"" + keyChar + "\" (" + (int)keyChar + ") "
        + KeyEvent.getKeyModifiersText(flags));
        if(keyCode==34 && currentSlice < img.getStackSize()) {
            currentSlice = currentSlice+1;
            reConstruct();
        }
        if(keyCode==33 && currentSlice>1) {
            currentSlice = currentSlice-1;
            reConstruct();
        }
        if ((flags & KeyEvent.SHIFT_MASK) != 0) {
            stepSize = 10;
        }  else {
            stepSize = 1;
        }
        if(keyCode==39) {
            flatdisplacementX[currentSlice] = flatdisplacementX[currentSlice] + stepSize;
            reConstruct();
        }
        if(keyCode==37) {
            flatdisplacementX[currentSlice] = flatdisplacementX[currentSlice] - stepSize;
            reConstruct();
        }
        if(keyCode==40) {
            flatdisplacementY[currentSlice] = flatdisplacementY[currentSlice] + stepSize;
            reConstruct();
        }
        if(keyCode==38) {
            flatdisplacementY[currentSlice] = flatdisplacementY[currentSlice] - stepSize;
            reConstruct();
        }
        if(keyCode==107) {
            flatrotation[currentSlice] = flatrotation[currentSlice] + stepSize/10;
            stack.getProcessor(currentSlice).insert(img.getStack().getProcessor(currentSlice),0,0);
            stack.getProcessor(currentSlice).setValue(0);
            stack.getProcessor(currentSlice).rotate(flatrotation[currentSlice]);
            reConstruct();
        }
        if(keyCode==109) {
            flatrotation[currentSlice] = flatrotation[currentSlice] - stepSize/10;
            stack.getProcessor(currentSlice).insert(img.getStack().getProcessor(currentSlice),0,0);
            stack.getProcessor(currentSlice).setValue(0);
            stack.getProcessor(currentSlice).rotate(flatrotation[currentSlice]);
            reConstruct();
        }
        if(keyCode==10) {
            ImageStack newStack = new ImageStack(img.getWidth(),img.getHeight(),img.getStack().getColorModel());
            for( int z = 1; z <=depth; z++){
                IJ.write("Stanrting :"+z);
                ImageProcessor tempProcessor = img.getStack().getProcessor(z).duplicate();
                tempProcessor.invertLut();
                tempProcessor.rotate(flatrotation[z]);
                newStack.addSlice(img.getStack().getSliceLabel(z), tempProcessor.createProcessor(img.getWidth(),img.getHeight()));  //lousy initialize
                newStack.getProcessor(z).copyBits(tempProcessor,flatdisplacementX[z],flatdisplacementY[z],Blitter.ADD);
                newStack.getProcessor(z).invertLut();
            }
            ImagePlus newImg = new ImagePlus( );
            newImg.setStack("Aligned_stack",newStack);
            ImageCanvas newCanvas = new ImageCanvas(newImg);
            new ImageWindow(newImg, newCanvas);
            IJ.write("Step4");
        }
        if(keyCode==76) {
            loadData();
        }
        if(keyCode==106) {
            saveData();
        }
        if(keyCode==86) {
            IJ.write("##### View Results #####");
            for(int  i=1;i<=depth;i++){
                IJ.write("Slice "+i+": "+flatdisplacementX[i]+","+flatdisplacementY[i]+","+flatrotation[i]);
            }
            IJ.write("########################");
            IJ.write(" ");
            IJ.write(" ");
        }
    }
    
    public void keyReleased(KeyEvent e) {}
    public void keyTyped(KeyEvent e) {}
    
    /** Returns the current list of modifier keys. */
    public String modifiers(int flags) {
        String s = " [ ";
        if (flags == 0) return "";
        if ((flags & KeyEvent.SHIFT_MASK) != 0) s += "Shift ";
        if ((flags & KeyEvent.CTRL_MASK) != 0) s += "Control ";
        if ((flags & KeyEvent.META_MASK) != 0) s += "Meta ";
        if ((flags & KeyEvent.ALT_MASK) != 0) s += "Alt ";
        s += "] ";
        return s;
    }
}

Align_Colors.java:

import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.plugin.*;
import ij.process.*;
import ij.gui.*;
import java.awt.event.*;
import java.io.*;

/**
 * This plugin implements the KeyListener interface and listens
 * for key events generated by the current image.
 */
public class Align_Colors implements PlugIn, KeyListener {
    ImagePlus img;
    ImageStack originalStack;
    String fileName;
    int[][] displacementX;
    int[][] displacementY;
    int[][] rotation;
    int depth,w,h;
    int currentColor; //0-red  1-green 2-blue
    int stepSize;
    
    
    
    void loadData() {
        try {
            if (!( new File(fileName).exists() )) {IJ.error("No input file");return;}
            
            int startColor = currentColor;
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            for(int i=1;i<=depth;i++) {
                img.setSlice(i);
                for(int c=0;c<3;c++){
                    String[] line = br.readLine().split(",");
                    displacementX[i][c]= new Integer(line[0]).intValue();
                    displacementY[i][c]= new Integer(line[1]).intValue();
                    rotation[i][c]= new Integer(line[2]).intValue();
                    currentColor=c;
                    refreshView();
                }
            }
            br.close();
            currentColor = startColor;
            return;
        } catch (IOException e) {
            IJ.showMessage("FileIO Error On Load: ", ""+e);
            return;
        }
        
    }
    
    void saveData() {
        try {
            new File(fileName).delete();
            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
            for(int i=1;i<=depth;i++) {
                for(int c=0;c<3;c++){
                    pw.print(displacementX[i][c]+","+displacementY[i][c]+","+rotation[i][c]+"\n");
                }
            }
            pw.flush();
            pw.close();
        } catch (IOException e) {
            IJ.showMessage("FileIO Error On Write: ", ""+e);
            return;
        }
    }
    
    
    
    void refreshView() {
        int currentSlice = img.getCurrentSlice();
        byte[][] cbytes = new byte[3][w*h];
        byte[][] obytes = new byte[3][w*h];
        
        ((ColorProcessor)(img.getStack().getProcessor(currentSlice))).getRGB(cbytes[0],cbytes[1],cbytes[2]);
        ((ColorProcessor)(originalStack.getProcessor(currentSlice))).getRGB(obytes[0],obytes[1],obytes[2]);
        ByteProcessor tempProcessor = new ByteProcessor(w,h,obytes[currentColor],null);
        tempProcessor.invertLut();
        tempProcessor.rotate(rotation[currentSlice][currentColor]);
        ByteProcessor tempProcessor2 = new ByteProcessor(w,h);
        tempProcessor2.insert(tempProcessor,displacementX[currentSlice][currentColor],displacementY[currentSlice][currentColor]);
        cbytes[currentColor]=(byte[])tempProcessor2.getPixels();
        ((ColorProcessor)(img.getStack().getProcessor(currentSlice))).setRGB(cbytes[0],cbytes[1],cbytes[2]);
        img.updateAndDraw();
    }
    
    public void run(String arg) {
        img = WindowManager.getCurrentImage();
        ImageWindow win = img.getWindow();
        ImageCanvas canvas = win.getCanvas();
        canvas.addKeyListener(this);
        
        
        fileName = img.getOriginalFileInfo().directory+img.getOriginalFileInfo().fileName+".colorAlignData";
        
        depth = img.getStackSize();
        w = img.getWidth();
        h = img.getHeight();
        originalStack = new ImageStack(w,h);
        for (int i = 1;i<=depth;i++) {
            IJ.showProgress((i-1)/depth);
            originalStack.addSlice(null,img.getStack().getProcessor(i).duplicate());
        }
        displacementX = new int[depth+1][3];
        displacementY = new int[depth+1][3];
        rotation = new int[depth+1][3];
    }
    
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        char keyChar = e.getKeyChar();
        int flags = e.getModifiers();
        IJ.log("keyCode=" + keyCode + " (" + KeyEvent.getKeyText(keyCode)
        + ") keyChar=\"" + keyChar + "\" (" + (int)keyChar + ") "
        + KeyEvent.getKeyModifiersText(flags));
        
        int currentSlice = img.getCurrentSlice();
        
        if ((flags & KeyEvent.SHIFT_MASK) != 0) {
            stepSize = 10;
        }  else {
            stepSize = 1;
        }
        
        if(keyCode==39) {
            displacementX[currentSlice][currentColor] = displacementX[currentSlice][currentColor] + stepSize;
            refreshView();
        }
        if(keyCode==37) {
            displacementX[currentSlice][currentColor] = displacementX[currentSlice][currentColor] - stepSize;
            refreshView();
        }
        if(keyCode==40) {
            displacementY[currentSlice][currentColor] = displacementY[currentSlice][currentColor] + stepSize;
            refreshView();
        }
        if(keyCode==38) {
            displacementY[currentSlice][currentColor] = displacementY[currentSlice][currentColor] - stepSize;
            refreshView();
        }
        if(keyCode==107) {
            rotation[currentSlice][currentColor] = rotation[currentSlice][currentColor] + stepSize/10;
            refreshView();
        }
        if(keyCode==109) {
            rotation[currentSlice][currentColor] = rotation[currentSlice][currentColor] - stepSize/10;
            refreshView();
        }
        if(keyCode==76) {
            loadData();
        }
        if(keyCode==106) {
            saveData();
        }
        if(keyCode==82) {
            currentColor=0;
        }
        if(keyCode==71) {
            currentColor=1;
        }
        if(keyCode==66) {
            currentColor=2;
        }
        if(keyCode==86) {
            IJ.write("##### View Results #####");
            for(int  i=1;i<=depth;i++){
                for(int c=0;c<3;c++){
                    IJ.write(displacementX[i][c]+","+displacementY[i][c]+","+rotation[i][c]);
                }
            }
            IJ.write("########################");
            IJ.write(" ");
            IJ.write(" ");
        }
    }
    
    public void keyReleased(KeyEvent e) {}
    public void keyTyped(KeyEvent e) {}
    
    /** Returns the current list of modifier keys. */
    public String modifiers(int flags) {
        String s = " [ ";
        if (flags == 0) return "";
        if ((flags & KeyEvent.SHIFT_MASK) != 0) s += "Shift ";
        if ((flags & KeyEvent.CTRL_MASK) != 0) s += "Control ";
        if ((flags & KeyEvent.META_MASK) != 0) s += "Meta ";
        if ((flags & KeyEvent.ALT_MASK) != 0) s += "Alt ";
        s += "] ";
        return s;
    }
}