/*- * #%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; import ij.ImageJ; import ij.gui.GenericDialog; import ij.plugin.PlugIn; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import mpicbg.spim.data.sequence.Channel; import mpicbg.spim.data.sequence.ViewDescription; import mpicbg.spim.data.sequence.ViewId; import mpicbg.spim.io.IOFunctions; import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccess; import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.gauss3.Gauss3; import net.imglib2.img.Img; import net.imglib2.img.imageplus.ImagePlusImgFactory; import net.imglib2.type.numeric.integer.UnsignedShortType; import net.imglib2.view.Views; import spim.fiji.plugin.queryXML.LoadParseQueryXML; import spim.fiji.plugin.util.GUIHelper; import spim.fiji.spimdata.SpimData2; import spim.fiji.spimdata.interestpoints.CorrespondingInterestPoints; import spim.fiji.spimdata.interestpoints.InterestPoint; import spim.fiji.spimdata.interestpoints.InterestPointList; import spim.process.fusion.export.DisplayImage; import spim.process.interestpointregistration.ChannelProcess; public class Visualize_Detections implements PlugIn { public static String[] detectionsChoice = new String[]{ "All detections", "Corresponding detections" }; public static int defaultDetections = 0; public static double defaultDownsample = 1.0; public static boolean defaultDisplayInput = false; public static class Params { final public ArrayList< ChannelProcess > channelsToProcess; final public int detections; final public double downsample; final public boolean displayInput; public Params( final ArrayList< ChannelProcess > channelsToProcess, final int detections, final double downsample, final boolean displayInput ) { this.channelsToProcess = channelsToProcess; this.detections = detections; this.downsample = downsample; this.displayInput = displayInput; } } @Override public void run( final String arg0 ) { // ask for everything but the channels final LoadParseQueryXML result = new LoadParseQueryXML(); if ( !result.queryXML( "visualize detections", true, false, true, true ) ) return; final List< ViewId > viewIds = SpimData2.getAllViewIdsSorted( result.getData(), result.getViewSetupsToProcess(), result.getTimePointsToProcess() ); final Params params = queryDetails( result.getData(), viewIds ); if ( params != null ) visualize( result.getData(), viewIds, params.channelsToProcess, params.detections, params.downsample, params.displayInput ); } public static Params queryDetails( final SpimData2 spimData, final List< ViewId > viewIds ) { // ask which channels have the objects we are searching for final List< Channel > channels = spimData.getSequenceDescription().getAllChannelsOrdered(); final int nAllChannels = spimData.getSequenceDescription().getAllChannelsOrdered().size(); // build up the dialog final GenericDialog gd = new GenericDialog( "Choose segmentations to display" ); if ( Interest_Point_Registration.defaultChannelLabels == null || Interest_Point_Registration.defaultChannelLabels.length != nAllChannels ) Interest_Point_Registration.defaultChannelLabels = new int[ nAllChannels ]; // check which channels and labels are available and build the choices final ArrayList< String[] > channelLabels = new ArrayList< String[] >(); int j = 0; for ( final Channel channel : channels ) { final String[] labels = Interest_Point_Registration.getAllInterestPointLabelsForChannel( spimData, viewIds, channel, "visualize" ); if ( labels == null ) return null; if ( Interest_Point_Registration.defaultChannelLabels[ j ] >= labels.length ) Interest_Point_Registration.defaultChannelLabels[ j ] = 0; String ch = channel.getName().replace( ' ', '_' ); gd.addChoice( "Interest_points_channel_" + ch, labels, labels[ Interest_Point_Registration.defaultChannelLabels[ j++ ] ] ); channelLabels.add( labels ); } gd.addChoice( "Display", detectionsChoice, detectionsChoice[ defaultDetections ] ); gd.addNumericField( "Downsample_detections_rendering", defaultDownsample, 2, 4, "times" ); gd.addCheckbox( "Display_input_images", defaultDisplayInput ); GUIHelper.addWebsite( gd ); gd.showDialog(); if ( gd.wasCanceled() ) return null; // assemble which channels have been selected with with label final ArrayList< ChannelProcess > channelsToProcess = new ArrayList< ChannelProcess >(); j = 0; for ( final Channel channel : channels ) { final int channelChoice = Interest_Point_Registration.defaultChannelLabels[ j ] = gd.getNextChoiceIndex(); if ( channelChoice < channelLabels.get( j ).length - 1 ) { String label = channelLabels.get( j )[ channelChoice ]; if ( label.contains( Interest_Point_Registration.warningLabel ) ) label = label.substring( 0, label.indexOf( Interest_Point_Registration.warningLabel ) ); channelsToProcess.add( new ChannelProcess( channel, label ) ); } ++j; } if ( channelsToProcess.size() == 0 ) { IOFunctions.println( "No channels selected. Quitting." ); return null; } for ( final ChannelProcess c : channelsToProcess ) IOFunctions.println( "displaying channel: " + c.getChannel().getId() + " label: '" + c.getLabel() + "'" ); final int detections = defaultDetections = gd.getNextChoiceIndex(); final double downsample = defaultDownsample = gd.getNextNumber(); final boolean displayInput = defaultDisplayInput = gd.getNextBoolean(); return new Params( channelsToProcess, detections, downsample, displayInput ); } public static void visualize( final SpimData2 spimData, final List< ViewId > viewIds, final ArrayList< ChannelProcess > channelsToProcess, final int detections, final double downsample, final boolean displayInput ) { // // load the images and render the segmentations // final DisplayImage di = new DisplayImage(); for ( final ViewId viewId : viewIds ) for ( final ChannelProcess c : channelsToProcess ) { // get the viewdescription final ViewDescription vd = spimData.getSequenceDescription().getViewDescription( viewId.getTimePointId(), viewId.getViewSetupId() ); // check if the view is present if ( !vd.isPresent() || vd.getViewSetup().getChannel().getId() != c.getChannel().getId() ) continue; // load and display final String name = "TP" + vd.getTimePointId() + "_Ch" + c.getChannel().getName() + "(label='" + c.getLabel() + "')_ill" + vd.getViewSetup().getIllumination().getName() + "_angle" + vd.getViewSetup().getAngle().getName(); final Interval interval; if ( displayInput ) { @SuppressWarnings( "unchecked" ) final RandomAccessibleInterval< UnsignedShortType > img = ( RandomAccessibleInterval< UnsignedShortType > ) spimData.getSequenceDescription().getImgLoader().getSetupImgLoader( vd.getViewSetupId() ).getImage( vd.getTimePointId() ); di.exportImage( img, name ); interval = img; } else { if ( !vd.getViewSetup().hasSize() ) { IOFunctions.println( "Cannot load image dimensions from XML for " + name + ", using min/max of all detections instead." ); interval = null; } else { interval = new FinalInterval( vd.getViewSetup().getSize() ); } } di.exportImage( renderSegmentations( spimData, viewId, c.getLabel(), detections, interval, downsample ), "seg of " + name ); } } protected static Img< UnsignedShortType > renderSegmentations( final SpimData2 data, final ViewId viewId, final String label, final int detections, Interval interval, final double downsample ) { final InterestPointList ipl = data.getViewInterestPoints().getViewInterestPointLists( viewId ).getInterestPointList( label ); if ( ipl.getInterestPoints() == null ) ipl.loadInterestPoints(); if ( interval == null ) { final int n = ipl.getInterestPoints().get( 0 ).getL().length; final long[] min = new long[ n ]; final long[] max = new long[ n ]; for ( int d = 0; d < n; ++d ) { min[ d ] = Math.round( ipl.getInterestPoints().get( 0 ).getL()[ d ] ) - 1; max[ d ] = Math.round( ipl.getInterestPoints().get( 0 ).getL()[ d ] ) + 1; } for ( final InterestPoint ip : ipl.getInterestPoints() ) { for ( int d = 0; d < n; ++d ) { min[ d ] = Math.min( min[ d ], Math.round( ip.getL()[ d ] ) - 1 ); max[ d ] = Math.max( max[ d ], Math.round( ip.getL()[ d ] ) + 1 ); } } interval = new FinalInterval( min, max ); } // downsample final long[] min = new long[ interval.numDimensions() ]; final long[] max = new long[ interval.numDimensions() ]; for ( int d = 0; d < interval.numDimensions(); ++d ) { min[ d ] = Math.round( interval.min( d ) / downsample ); max[ d ] = Math.round( interval.max( d ) / downsample ) ; } interval = new FinalInterval( min, max ); final Img< UnsignedShortType > s = new ImagePlusImgFactory< UnsignedShortType >().create( interval, new UnsignedShortType() ); final RandomAccess< UnsignedShortType > r = Views.extendZero( s ).randomAccess(); final int n = s.numDimensions(); final long[] tmp = new long[ n ]; if ( detections == 0 ) { IOFunctions.println( "Visualizing " + ipl.getInterestPoints().size() + " detections." ); for ( final InterestPoint ip : ipl.getInterestPoints() ) { for ( int d = 0; d < n; ++d ) tmp[ d ] = Math.round( ip.getL()[ d ] / downsample ); r.setPosition( tmp ); r.get().set( 65535 ); } } else { final HashMap< Integer, InterestPoint > map = new HashMap< Integer, InterestPoint >(); for ( final InterestPoint ip : ipl.getInterestPoints() ) map.put( ip.getId(), ip ); if ( ipl.getCorrespondingInterestPoints() == null ) { if ( !ipl.loadCorrespondingInterestPoints() ) { IOFunctions.println( "No corresponding detections available, the dataset was not registered using these detections." ); return s; } } IOFunctions.println( "Visualizing " + ipl.getCorrespondingInterestPoints().size() + " corresponding detections." ); for ( final CorrespondingInterestPoints ip : ipl.getCorrespondingInterestPoints() ) { for ( int d = 0; d < n; ++d ) tmp[ d ] = Math.round( map.get( ip.getDetectionId() ).getL()[ d ] / downsample ); r.setPosition( tmp ); r.get().set( 65535 ); } } try { Gauss3.gauss( new double[]{ 2, 2, 2 }, Views.extendZero( s ), s ); } catch ( Exception e ) { IOFunctions.println( "Gaussian Convolution of detections failed: " + e ); e.printStackTrace(); } catch ( OutOfMemoryError e ) { IOFunctions.println( "Gaussian Convolution of detections failed due to out of memory, just showing plain image: " + e ); } return s; } public static void main( final String[] args ) { new ImageJ(); new Visualize_Detections().run( null ); } }