ICY Version 1.0.1.0

Tutorial: Plugin Communication : SwimmingPool : How to read and watch/listen data event of the swimming pool

 *public class SwimmingPoolListenerTutorial extends Plugin implements PluginImageAnalysis , SwimmingPoolListener {

           @Override
           public void compute() {

                      // We register this class as a listener of the swimmingPool
                      Icy.getMainInterface().getSwimmingPool().addListener( this );

                      new AnnounceFrame( "Swimming pool listener example: I am listening/watching the swimmingpool." );
                      
                      // watch if objects are already in the swimming pool:
                      for ( SwimmingObject swimmingObject : Icy.getMainInterface().getSwimmingPool().getObjects() )
                      {
                                 if ( swimmingObject.getObject() instanceof Point2D )
                                 {
                                            Point2D point = (Point2D) swimmingObject.getObject();
                                            new AnnounceFrame("Swimming pool listener example: There is already an object in the swimming pool ! Its coordinates are "+ point.getX() + "," + point.getY() );
                                 }
                      }
                      
           }

           @Override
           public void swimmingPoolChangeEvent(SwimmingPoolEvent event) {

                      // an object has been added in the swimming pool !
                      if ( event.getType() == SwimmingPoolEventType.ELEMENT_ADDED )
                      {
                                 // Can we manage this type ?
                                 if ( event.getResult().getObject() instanceof Point2D )
                                 {
                                            // yes, we know it, let's process it.
                                            Point2D point = (Point2D) event.getResult().getObject();
                                            new AnnounceFrame("Swimming pool listener example: A point has been dropped ! Its coordinates are "+ point.getX() + "," + point.getY() );
                                 }else
                                 {
                                            // no, we don't know what we should do with it.
                                            new AnnounceFrame( "Swimming pool listener example: Something has been dropped, but I don't know how to handle it." );              
                                 }
                      }

           }

           
           
}

 *

This is a swimming pool listener tutorial. Use it with SwimmingPoolEmitterTutorial.

The swimming pool is a place where any plugin can access, listen, create, delete or transform objects. This is the ultimate flexibility to create communication between plugins.

This tutorial explain how to register a listener, and listen to a certain type of object.

Author:
Fabrice de Chaumont and Stephane Dallongeville
 *public class ProcessingFromROI extends Plugin implements PluginImageAnalysis, SequenceListener, ViewerListener
{
    private Viewer viewer;
    private Sequence sequence;
    private AbstractPainter painter;
    BufferedImage img;
    private int[] imgData;

    @Override
    public void compute()
    {
        viewer = getFocusedViewer();

        // no viewer has been found ?
        if (viewer == null)
        {
            // display an information message as we need an opened sequence
            MessageDialog.showDialog("This example needs a sequence to start. Please load an image file.",
                    MessageDialog.INFORMATION_MESSAGE);
            return;
        }

        // we should avoid direct sequence reference but it really help there
        sequence = viewer.getSequence();

        // display an announcement with Plugin description
        new AnnounceFrame("This example show how do localized operation on image from ROI");
        // no ROI2D in sequence
        if (!sequence.hasROI(ROI2D.class))
            new AnnounceFrame("Add a ROI to the sequence to see plugin action");

        // define a painter to just draw the image over the sequence
        painter = new AbstractPainter()
        {
            @Override
            public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas)
            {
                // just draw the image over the sequence
                g.drawImage(img, null, 0, 0);
            }
        };

        // add the painter to the sequence
        sequence.addPainter(painter);

        // build an ARGB image with same dimension than sequence
        img = new BufferedImage(sequence.getSizeX(), sequence.getSizeY(), BufferedImage.TYPE_INT_ARGB);
        // get internal image data reference
        imgData = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

        // listen viewer changes so we know when current displayed image change
        viewer.addListener(this);
        // listen sequence changes so we know when sequence rois are modified
        sequence.addListener(this);

        refresh();
    }

    // we call this method when we want to terminate plugin execution
    private void close()
    {
        // remove viewer listener
        viewer.removeListener(this);
        // remove sequence listener
        sequence.removeListener(this);
        // remove the painter from the sequence (same as painter.detachFromAll())
        sequence.removePainter(painter);

        // free sequence reference
        viewer = null;
        sequence = null;
    }

    private void refresh()
    {
        // clear image
        Arrays.fill(imgData, 0);

        final IcyBufferedImage currentImage = getFocusedImage();

        if (currentImage != null)
        {
            // get image bounds (rectangle defining height and width of image)
            final Rectangle imageBounds = currentImage.getBounds();

            BooleanMask2D globalMask = null;

            // compute global boolean mask of all ROI2D contained in the sequence
            for (ROI2D roi : sequence.getROI2Ds())
            {
                // get intersection between image and roi bounds
                final Rectangle intersect = roi.getBounds().intersection(imageBounds);
                // get the boolean mask of roi (optimized from intersection bounds)
                final boolean[] mask = roi.getAsBooleanMask(intersect);

                // update global mask
                if (globalMask == null)
                    globalMask = new BooleanMask2D(intersect, mask);
                else
                    globalMask.union(intersect, mask);
            }

            // process only if global mask is not empty
            if ((globalMask != null) && (!globalMask.bounds.isEmpty()))
            {
                final Rectangle bounds = globalMask.bounds;
                final boolean[] mask = globalMask.mask;

                // calculate offset
                int offMsk = 0;
                int offImg = (bounds.y * imageBounds.width) + bounds.x;

                // do process only on data contained in ROI
                for (int y = 0; y < bounds.height; y++)
                {
                    // override all contained pixels with half transparent green
                    for (int x = 0; x < bounds.width; x++)
                        if (mask[offMsk + x])
                            imgData[offImg + x] = 0x8000FF00;

                    offMsk += bounds.width;
                    offImg += imageBounds.width;
                }
            }
        }

        // notify that our painter has changed (image data modified)
        // this method is a facility of AbstractPainter
        // this is equivalent to sequence.painterChanged(painter);
        painter.changed();
    }

    // called when sequence has changed
    @Override
    public void sequenceChanged(SequenceEvent sequenceEvent)
    {
        // we want to know about sequence roi changes
        switch (sequenceEvent.getSourceType())
        {
            case SEQUENCE_ROI:
                // roi change --> refresh
                refresh();
                break;
        }
    }

    // called when sequence is closed (last viewer containing sequence has changed
    @Override
    public void sequenceClosed(Sequence sequence)
    {
    }

    @Override
    public void viewerChanged(Viewer viewer, ViewerChangedEventType eventType)
    {
        // we want to know about navigation change (current displayed image change)
        switch (eventType)
        {
            case POSITION_T_CHANGED:
            case POSITION_Z_CHANGED:
                // refresh
                refresh();
                break;
        }
    }

    @Override
    public void viewerClosed(Viewer viewer)
    {
        // end plugin execution
        close();
    }
}

 *

This class show how we can use ROI to do localized operation on image

Author:
Stephane
 All Classes Functions Variables