/*- * #%L * Fiji distribution of ImageJ for the life sciences. * %% * Copyright (C) 2007 - 2017 Fiji developers. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package spim.fiji.plugin.removedetections; import ij.ImagePlus; import ij.gui.OvalRoi; import ij.gui.Overlay; import ij.gui.Roi; import java.awt.Button; import java.awt.Color; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Date; import java.util.List; import mpicbg.spim.data.sequence.ViewDescription; import mpicbg.spim.data.sequence.ViewId; import mpicbg.spim.io.IOFunctions; import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImgFactory; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.type.numeric.real.FloatType; import spim.fiji.spimdata.SpimData2; import spim.fiji.spimdata.interestpoints.InterestPoint; import spim.fiji.spimdata.interestpoints.InterestPointList; import spim.fiji.spimdata.interestpoints.ViewInterestPointLists; import spim.fiji.spimdata.interestpoints.ViewInterestPoints; import spim.process.fusion.deconvolution.ExtractPSF; public class InteractiveProjections { public static double size = 2; final Frame frame; protected boolean isRunning, wasCanceled; protected ImagePlus imp; protected List< InterestPoint > ipList; final protected List< Thread > runAfterFinished; public InteractiveProjections( final SpimData2 spimData, final ViewDescription vd, final String label, final String newLabel, final int projectionDim ) { this.isRunning = true; this.wasCanceled = false; this.runAfterFinished = new ArrayList< Thread >(); IOFunctions.println( "(" + new Date( System.currentTimeMillis() ) + ": Loading image ..." ); RandomAccessibleInterval< FloatType > img = spimData.getSequenceDescription().getImgLoader().getSetupImgLoader( vd.getViewSetupId() ).getFloatImage( vd.getTimePointId(), false ); IOFunctions.println( "(" + new Date( System.currentTimeMillis() ) + ": Computing max projection along dimension " + projectionDim + " ..." ); final Img< FloatType > maxProj = ExtractPSF.computeMaxProjection( img, new ArrayImgFactory< FloatType >(), projectionDim ); this.imp = showProjection( maxProj ); IOFunctions.println( "(" + new Date( System.currentTimeMillis() ) + ": Loading & drawing interest points ..." ); this.ipList = loadInterestPoints( spimData, vd, label ); drawProjectedInterestPoints( imp, ipList, projectionDim ); IOFunctions.println( "(" + new Date( System.currentTimeMillis() ) + ": " + ipList.size() + " points displayed ... " ); frame = new Frame( "Remove detections" ); frame.setSize( 300, 180 ); /* Instantiation */ final GridBagLayout layout = new GridBagLayout(); final GridBagConstraints c = new GridBagConstraints(); final Button removeIn = new Button( "Remove all detections INside ROI" ); final Button removeOut = new Button( "Remove all detections OUTside ROI" ); final Button done = new Button( "Done" ); final Button cancel = new Button( "Cancel" ); /* Location */ frame.setLayout( layout ); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; frame.add( removeIn, c ); ++c.gridy; frame.add( removeOut, c ); c.insets = new Insets( 20,0,0,0 ); ++c.gridy; frame.add( done, c ); c.insets = new Insets( 0,0,0,0 ); ++c.gridy; frame.add( cancel, c ); removeIn.addActionListener( new RemoveInsideROIButtonListener( imp, ipList, projectionDim, true ) ); removeOut.addActionListener( new RemoveInsideROIButtonListener( imp, ipList, projectionDim, false ) ); done.addActionListener( new FinishedButtonListener( frame, false ) ); cancel.addActionListener( new FinishedButtonListener( frame, true ) ); frame.setVisible( true ); } public void runWhenDone( final Thread thread ) { this.runAfterFinished.add( thread ); } public List< InterestPoint > getInterestPointList() { return ipList; } public boolean isRunning() { return isRunning; } public boolean wasCanceled() { return wasCanceled; } protected static void drawProjectedInterestPoints( final ImagePlus imp, final List< InterestPoint > ipList, final int projectionDim ) { final int xDim = getXDim( projectionDim ); final int yDim = getYDim( projectionDim ); // extract peaks to show Overlay o = imp.getOverlay(); if ( o == null ) { o = new Overlay(); imp.setOverlay( o ); } o.clear(); for ( final InterestPoint ip : ipList ) { final double x = ip.getL()[ xDim ]; final double y = ip.getL()[ yDim ]; final OvalRoi or = new OvalRoi( Math.round( x - size ), Math.round( y - size ), Math.round( size * 2 ), Math.round( size * 2 ) ); or.setStrokeColor( Color.green ); o.add( or ); } imp.updateAndDraw(); } protected static int getXDim( final int projectionDim ) { if ( projectionDim == 2 ) return 0; else if ( projectionDim == 1 ) return 0; else return 1; } protected static int getYDim( final int projectionDim ) { if ( projectionDim == 2 ) return 1; else if ( projectionDim == 1 ) return 2; else return 2; } protected List< InterestPoint > loadInterestPoints( final SpimData2 spimData, final ViewId id, final String label ) { final ViewInterestPoints interestPoints = spimData.getViewInterestPoints(); final ViewInterestPointLists lists = interestPoints.getViewInterestPointLists( id ); final InterestPointList list = lists.getInterestPointList( label ); if ( list.getInterestPoints() == null ) list.loadInterestPoints(); final ArrayList< InterestPoint > newList = new ArrayList< InterestPoint >(); for ( final InterestPoint p : list.getInterestPoints() ) newList.add( new InterestPoint( p.getId(), p.getL().clone() ) ); return newList; } protected ImagePlus showProjection( final Img< FloatType > img ) { final ImagePlus imp = ImageJFunctions.wrapFloat( img, "Max Projection" ); imp.show(); return imp; } protected void close( final Frame parent ) { if ( parent != null ) parent.dispose(); if ( imp != null ) imp.close(); for ( final Thread t : runAfterFinished ) t.start(); isRunning = false; } protected class RemoveInsideROIButtonListener implements ActionListener { final ImagePlus imp; final List< InterestPoint > ipList; final int projectionDim, xDim, yDim; final boolean inside; public RemoveInsideROIButtonListener( final ImagePlus imp, final List< InterestPoint > ipList, final int projectionDim, final boolean inside ) { this.imp = imp; this.ipList = ipList; this.projectionDim = projectionDim; this.inside = inside; this.xDim = getXDim( projectionDim ); this.yDim = getYDim( projectionDim ); } @Override public void actionPerformed( final ActionEvent arg0 ) { final Roi roi = imp.getRoi(); if ( roi == null ) { IOFunctions.println( "No ROI selected in max projection image." ); } else { int count = ipList.size(); for ( int i = ipList.size() - 1; i >= 0; --i ) { final double[] l = ipList.get( i ).getL(); final boolean contains = roi.contains( (int)Math.round( l[ xDim ] ), (int)Math.round( l[ yDim ] ) ); if ( inside && contains || !inside && !contains ) ipList.remove( i ); } drawProjectedInterestPoints( imp, ipList, projectionDim ); IOFunctions.println( "(" + new Date( System.currentTimeMillis() ) + ": " + ipList.size() + " points remaining, removed " + (count - ipList.size()) + " points ... " ); } } } protected class FinishedButtonListener implements ActionListener { final Frame parent; final boolean frameWasCanceled; public FinishedButtonListener( final Frame parent, final boolean frameWasCanceled ) { this.parent = parent; this.frameWasCanceled = frameWasCanceled; } @Override public void actionPerformed( final ActionEvent arg0 ) { close( parent ); wasCanceled = this.frameWasCanceled; } } }