001/**
002 * 
003 */
004package plugins.tutorial.training;
005
006import icy.gui.dialog.MessageDialog;
007import icy.image.IcyBufferedImage;
008import icy.math.ArrayMath;
009import icy.plugin.abstract_.PluginActionable;
010import icy.sequence.Sequence;
011import icy.type.collection.array.Array1DUtil;
012
013/**
014 * Basic image processing plugin example: apply a maximum intensity projection along Z axis on the
015 * active sequence
016 * 
017 * @author Stephane
018 */
019public class MaximumZProjectionPlugin extends PluginActionable
020{
021
022    @Override
023    public void run()
024    {
025        Sequence sequence = getActiveSequence();
026
027        // check if a sequence is opened
028        if (sequence == null)
029        {
030            MessageDialog.showDialog("Please open a sequence to use this plugin.", MessageDialog.WARNING_MESSAGE);
031            return;
032        }
033
034        // create a new empty sequence by using the original sequence name
035        Sequence result = new Sequence(sequence.getName() + " - Z projection");
036
037        // start sequence modification
038        result.beginUpdate();
039        try
040        {
041            // for each frame of the sequence
042            for (int t = 0; t < sequence.getSizeT(); t++)
043            {
044                // compute the Z projection for the specified frame of sequence
045                IcyBufferedImage image = getMaxZProjection(sequence, t);
046                // set the image result at frame position t in the result Sequence
047                result.setImage(t, 0, image);
048            }
049        }
050        finally
051        {
052            // we are done with sequence modification
053            result.endUpdate();
054        }
055
056        // make the sequence visible (add it to the GUI)
057        addSequence(result);
058    }
059
060    static IcyBufferedImage getMaxZProjection(Sequence sequence, int t)
061    {
062        // create a new image with same size and data type as the original Sequence
063        IcyBufferedImage result = new IcyBufferedImage(sequence.getSizeX(), sequence.getSizeY(), sequence.getSizeC(),
064                sequence.getDataType_());
065
066        // for each channel of the input Sequence
067        for (int c = 0; c < sequence.getSizeC(); c++)
068        {
069            // get a direct reference on the XY planar image data array
070            Object dataArray = result.getDataXY(c);
071
072            // convert the result image data to double type for calculations
073            double[] doubleArray = Array1DUtil.arrayToDoubleArray(dataArray, result.isSignedDataType());
074
075            // for each Z slice of the input Sequence
076            for (int z = 0; z < sequence.getSizeZ(); z++)
077                // compute the maximum between the specified slice data and the result array
078                projectMax(sequence, t, z, c, doubleArray);
079
080            // convert back the double array to original image data type
081            Array1DUtil.doubleArrayToArray(doubleArray, dataArray);
082
083            // just to let the image know the data has changed (internal updates and view refresh) and also to update cache for volatile image
084            result.setDataXY(0, dataArray);
085        }
086
087        return result;
088    }
089
090    static void projectMax(Sequence sequence, int t, int z, int c, double[] result)
091    {
092        // get XY planar image data array for the specified T, Z and C position
093        Object dataArray = sequence.getDataXY(t, z, c);
094
095        // convert to double data array
096        double[] imgDoubleArray = Array1DUtil.arrayToDoubleArray(dataArray, sequence.isSignedDataType());
097
098        // get the maximum from the 2 input arrays and save the result
099        // into the result array by using the ArrayMath.max(..) method
100        ArrayMath.max(result, imgDoubleArray, result);
101    }
102}