/*- * #%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.interestpointdetection; import ij.ImagePlus; import ij.gui.GenericDialog; import java.util.HashMap; import java.util.List; import mpicbg.imglib.image.Image; import mpicbg.imglib.type.numeric.real.FloatType; import mpicbg.imglib.wrapper.ImgLib2; import mpicbg.spim.data.sequence.Channel; import mpicbg.spim.data.sequence.TimePoint; import mpicbg.spim.data.sequence.ViewDescription; import mpicbg.spim.data.sequence.ViewId; import mpicbg.spim.io.IOFunctions; import mpicbg.spim.segmentation.InteractiveIntegral; import net.imglib2.RandomAccessibleInterval; import net.imglib2.img.Img; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.realtransform.AffineTransform3D; import spim.fiji.spimdata.SpimData2; import spim.fiji.spimdata.interestpoints.InterestPoint; import spim.process.interestpointdetection.ProcessDOM; public class DifferenceOfMean extends DifferenceOf { public static int defaultR1 = 2; public static int defaultR2 = 3; public static double defaultT = 0.02; public static int defaultRadius1[]; public static int defaultRadius2[]; public static double defaultThreshold[]; public static boolean defaultFindMin[]; public static boolean defaultFindMax[]; int[] radius1; int[] radius2; double[] threshold; boolean[] findMin; boolean[] findMax; public DifferenceOfMean( final SpimData2 spimData, final List< ViewId > viewIdsToProcess ) { super( spimData, viewIdsToProcess ); } @Override public String getDescription() { return "Difference-of-Mean (Integral image based)"; } @Override public DifferenceOfMean newInstance( final SpimData2 spimData, final List< ViewId > viewIdsToProcess ) { return new DifferenceOfMean( spimData, viewIdsToProcess ); } @Override public HashMap< ViewId, List< InterestPoint > > findInterestPoints( final TimePoint t ) { final HashMap< ViewId, List< InterestPoint > > interestPoints = new HashMap< ViewId, List< InterestPoint > >(); for ( final ViewDescription vd : SpimData2.getAllViewIdsForTimePointSorted( spimData, viewIdsToProcess, t ) ) { // make sure not everything crashes if one file is missing try { // // open the corresponding image (if present at this timepoint) // long time1 = System.currentTimeMillis(); if ( !vd.isPresent() ) continue; final Channel c = vd.getViewSetup().getChannel(); final AffineTransform3D correctCoordinates = new AffineTransform3D(); final RandomAccessibleInterval< net.imglib2.type.numeric.real.FloatType > input = openAndDownsample( spimData, vd, correctCoordinates ); long time2 = System.currentTimeMillis(); benchmark.openFiles += time2 - time1; preSmooth( input ); final Image< FloatType > img = ImgLib2.wrapFloatToImgLib1( (Img<net.imglib2.type.numeric.real.FloatType>)input ); // // compute Difference-of-Mean // List< InterestPoint > ips = ProcessDOM.compute( img, (Img<net.imglib2.type.numeric.real.FloatType>)input, radius1[ c.getId() ], radius2[ c.getId() ], (float)threshold[ c.getId() ], localization, imageSigmaX, imageSigmaY, imageSigmaZ, findMin[ c.getId() ], findMax[ c.getId() ], minIntensity, maxIntensity, limitDetections); img.close(); correctForDownsampling( ips, correctCoordinates ); if ( limitDetections ) ips = limitList( maxDetections, maxDetectionsTypeIndex, ips ); interestPoints.put( vd, ips ); benchmark.computation += System.currentTimeMillis() - time2; } catch ( Exception e ) { IOFunctions.println( "An error occured (DOM): " + e ); IOFunctions.println( "Failed to segment angleId: " + vd.getViewSetup().getAngle().getId() + " channelId: " + vd.getViewSetup().getChannel().getId() + " illumId: " + vd.getViewSetup().getIllumination().getId() + ". Continuing with next one." ); e.printStackTrace(); } } return interestPoints; } @Override protected boolean setDefaultValues( final Channel channel, final int brightness ) { final int channelId = channel.getId(); this.radius1[ channelId ] = defaultR1; this.radius2[ channelId ] = defaultR2; this.findMin[ channelId ] = false; this.findMax[ channelId ] = true; if ( brightness == 0 ) this.threshold[ channelId ] = 0.0025f; else if ( brightness == 1 ) this.threshold[ channelId ] = 0.02f; else if ( brightness == 2 ) this.threshold[ channelId ] = 0.075f; else if ( brightness == 3 ) this.threshold[ channelId ] = 0.25f; else return false; return true; } @Override protected boolean setAdvancedValues( final Channel channel ) { final int channelId = channel.getId(); final GenericDialog gd = new GenericDialog( "Advanced values for channel " + channel.getName() ); String ch; if ( this.channelsToProcess.size() > 1 ) ch = "_" + channel.getName().replace( ' ', '_' ); else ch = ""; gd.addMessage( "Advanced values for channel " + channel.getName() ); gd.addNumericField( "Radius_1" + ch, defaultRadius1[ channelId ], 0 ); gd.addNumericField( "Radius_2" + ch, defaultRadius2[ channelId ], 0 ); gd.addNumericField( "Threshold" + ch, defaultThreshold[ channelId ], 4 ); gd.addCheckbox( "Find_minima" + ch, defaultFindMin[ channelId ] ); gd.addCheckbox( "Find_maxima" + ch, defaultFindMax[ channelId ] ); gd.showDialog(); if ( gd.wasCanceled() ) return false; this.radius1[ channelId ] = defaultRadius1[ channelId ] = (int)Math.round( gd.getNextNumber() ); this.radius2[ channelId ] = defaultRadius2[ channelId ] = (int)Math.round( gd.getNextNumber() ); this.threshold[ channelId ] = defaultThreshold[ channelId ] = gd.getNextNumber(); this.findMin[ channelId ] = defaultFindMin[ channelId ] = gd.getNextBoolean(); this.findMax[ channelId ] = defaultFindMax[ channelId ] = gd.getNextBoolean(); return true; } @Override protected boolean setInteractiveValues( final Channel channel ) { final ViewId view = getViewSelection( "Interactive Difference-of-Mean", "Please select view to use for channel " + channel.getName(), channel ); if ( view == null ) return false; final ViewDescription viewDescription = spimData.getSequenceDescription().getViewDescription( view.getTimePointId(), view.getViewSetupId() ); if ( !viewDescription.isPresent() ) { IOFunctions.println( "You defined the view you selected as not present at this timepoint." ); IOFunctions.println( "timepoint: " + viewDescription.getTimePoint().getName() + " angle: " + viewDescription.getViewSetup().getAngle().getName() + " channel: " + viewDescription.getViewSetup().getChannel().getName() + " illum: " + viewDescription.getViewSetup().getIllumination().getName() ); return false; } RandomAccessibleInterval< net.imglib2.type.numeric.real.FloatType > img = openAndDownsample( spimData, viewDescription, new AffineTransform3D() ); if ( img == null ) { IOFunctions.println( "View not found: " + viewDescription ); return false; } preSmooth( img ); final ImagePlus imp = ImageJFunctions.wrapFloat( img, "" ).duplicate(); img = null; imp.setDimensions( 1, imp.getStackSize(), 1 ); imp.setTitle( "tp: " + viewDescription.getTimePoint().getName() + " viewSetup: " + viewDescription.getViewSetupId() ); imp.show(); imp.setSlice( imp.getStackSize() / 2 ); final InteractiveIntegral ii = new InteractiveIntegral(); final int channelId = channel.getId(); ii.setInitialRadius( Math.round( defaultRadius1[ channelId ] ) ); ii.setThreshold( (float)defaultThreshold[ channelId ] ); ii.setLookForMinima( defaultFindMin[ channelId ] ); ii.setLookForMaxima( defaultFindMax[ channelId ] ); ii.setMinIntensityImage( minIntensity ); // if is Double.NaN will be ignored ii.setMaxIntensityImage( maxIntensity ); // if is Double.NaN will be ignored ii.run( null ); while ( !ii.isFinished() ) { try { Thread.sleep( 100 ); } catch (InterruptedException e) {} } imp.close(); if ( ii.wasCanceld() ) return false; this.radius1[ channelId ] = defaultRadius1[ channelId ] = ii.getRadius1(); this.radius2[ channelId ] = defaultRadius2[ channelId ] = ii.getRadius2(); this.threshold[ channelId ] = defaultThreshold[ channelId ] = ii.getThreshold(); this.findMin[ channelId ] = defaultFindMin[ channelId ] = ii.getLookForMinima(); this.findMax[ channelId ] = defaultFindMax[ channelId ] = ii.getLookForMaxima(); return true; } /** * This is only necessary to make static objects so that the ImageJ dialog remembers choices * for the right channel * * @param numChannels - the TOTAL number of channels (not only the ones to process) */ @Override protected void init( final int numChannels ) { radius1 = new int[ numChannels ]; radius2 = new int[ numChannels ]; threshold = new double[ numChannels ]; findMin = new boolean[ numChannels ]; findMax = new boolean[ numChannels ]; if ( defaultRadius1 == null || defaultRadius1.length != numChannels ) { defaultRadius1 = new int[ numChannels ]; defaultRadius2 = new int[ numChannels ]; defaultThreshold = new double[ numChannels ]; defaultFindMin = new boolean[ numChannels ]; defaultFindMax = new boolean[ numChannels ]; for ( int c = 0; c < numChannels; ++c ) { defaultRadius1[ c ] = defaultR1; defaultRadius2[ c ] = defaultR2; defaultThreshold[ c ] = defaultT; defaultFindMin[ c ] = false; defaultFindMax[ c ] = true; } } } @Override public String getParameters( final int channelId ) { return "DOM r1=" + radius1[ channelId ] + " t=" + threshold[ channelId ] + " min=" + findMin[ channelId ] + " max=" + findMax[ channelId ] + " imageSigmaX=" + imageSigmaX + " imageSigmaY=" + imageSigmaY + " imageSigmaZ=" + imageSigmaZ + " downsampleXY=" + downsampleXY + " downsampleZ=" + downsampleZ + " additionalSigmaX=" + additionalSigmaX + " additionalSigmaY=" + additionalSigmaY + " additionalSigmaZ=" + additionalSigmaZ + " minIntensity=" + minIntensity + " maxIntensity=" + maxIntensity; } @Override protected void addAddtionalParameters( final GenericDialog gd ) {} @Override protected boolean queryAdditionalParameters( final GenericDialog gd ) { return true; } }