/*- * #%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 fiji.plugin; import fiji.Debug; import fiji.plugin.timelapsedisplay.GraphFrame; import fiji.plugin.timelapsedisplay.TimeLapseDisplay; import fiji.util.gui.GenericDialogPlus; import ij.IJ; import ij.ImagePlus; import ij.gui.DialogListener; import ij.gui.GenericDialog; import ij.gui.MultiLineLabel; import ij.plugin.PlugIn; import java.awt.AWTEvent; import java.awt.Checkbox; import java.awt.TextField; import java.awt.event.TextEvent; import java.io.File; import java.util.ArrayList; import java.util.Date; import mpicbg.imglib.container.array.ArrayContainerFactory; import mpicbg.imglib.container.cell.CellContainerFactory; import mpicbg.imglib.image.Image; import mpicbg.imglib.image.display.imagej.ImageJFunctions; import mpicbg.imglib.io.LOCI; import mpicbg.imglib.multithreading.SimpleMultiThreading; import mpicbg.imglib.type.numeric.real.FloatType; import mpicbg.spim.Reconstruction; import mpicbg.spim.io.ConfigurationParserException; import mpicbg.spim.io.IOFunctions; import mpicbg.spim.io.SPIMConfiguration; import mpicbg.spim.io.SPIMConfiguration.SegmentationTypes; import mpicbg.spim.segmentation.InteractiveDoG; import mpicbg.spim.segmentation.InteractiveIntegral; import spim.Threads; import spim.fiji.plugin.util.GUIHelper; import spimopener.SPIMExperiment; public class Bead_Registration implements PlugIn { final private String myURL = "http://fly.mpi-cbg.de/preibisch"; final private String paperURL = "http://www.nature.com/nmeth/journal/v7/n6/full/nmeth0610-418.html"; final String beadRegistration[] = new String[] { "Single-channel", "Multi-channel (same beads visible in different channels)" }; final String beadDetectionType[] = new String[] { "Difference-of-Gaussian", "Difference-of-Mean (Integral image based)" }; public static int defaultBeadRegistration = 0; public static int defaultBeadDetectionType = 1; @Override public void run(String arg0) { // output to IJ.log IOFunctions.printIJLog = true; final GenericDialog gd = new GenericDialog( "Bead based registration" ); gd.addChoice( "Select_type_of_registration", beadRegistration, beadRegistration[ defaultBeadRegistration ] ); gd.addChoice( "Select_type_of_detection", beadDetectionType, beadDetectionType[ defaultBeadDetectionType ] ); gd.addMessage( "Please note that the SPIM Registration is based on a publication.\n" + "If you use it successfully for your research please be so kind to cite our work:\n" + "Preibisch et al., Nature Methods (2010), 7(6):418-419\n" ); MultiLineLabel text = (MultiLineLabel) gd.getMessage(); GUIHelper.addHyperLinkListener( text, paperURL ); gd.showDialog(); if ( gd.wasCanceled() ) return; final int choice = defaultBeadRegistration = gd.getNextChoiceIndex(); final int choiceType = defaultBeadDetectionType = gd.getNextChoiceIndex(); final SPIMConfiguration conf; if ( choice == 0 ) conf = singleChannel( choiceType ); else conf = multiChannel( choiceType ); // cancelled if ( conf == null ) return; // get filenames and so on... if ( !init( conf ) ) return; // this is only registration conf.registerOnly = true; // if we do not do timelapseregistration we can just go ahead and // display the result if wanted if ( !timeLapseRegistration ) { conf.timeLapseRegistration = false; conf.collectRegistrationStatistics = true; final Reconstruction reconstruction = new Reconstruction( conf ); if ( reconstruction.getSPIMConfiguration().file.length > 1 && defaultTimeLapseRegistration == 0 ) TimeLapseDisplay.plotData( reconstruction.getRegistrationStatistics(), -1, false ); } else { // now compute or load the inter-timepoint registration conf.timeLapseRegistration = false; conf.collectRegistrationStatistics = true; // compute per-timepoint registration Reconstruction reconstruction = new Reconstruction( conf ); if ( defaultTimeLapseRegistration == 0 ) { // manually select timepoint final GraphFrame gf = TimeLapseDisplay.plotData( reconstruction.getRegistrationStatistics(), -1, true ); int lastRefTP = -1; do { lastRefTP = gf.getReferenceTimePoint(); SimpleMultiThreading.threadWait( 1000 ); } while ( gf.getReferenceTimePoint() == lastRefTP ); conf.referenceTimePoint = gf.getReferenceTimePoint(); } else if ( defaultTimeLapseRegistration == 1 ) { conf.referenceTimePoint = defaultTimePoint; } else { // automatically select, but still show the display conf.referenceTimePoint = TimeLapseDisplay.getOptimalTimePoint( reconstruction.getRegistrationStatistics() ); TimeLapseDisplay.plotData( reconstruction.getRegistrationStatistics(), conf.referenceTimePoint, false ); } // and now the timelapse-registration conf.timeLapseRegistration = true; conf.readRegistration = false; reconstruction = new Reconstruction( conf ); } } public static String spimDataDirectory = ""; public static String timepoints = "18"; public static String fileNamePattern = "spim_TL{t}_Angle{a}.lsm"; public static String angles = "0-270:45"; public static boolean loadSegmentation = false; public static int relocalize = 1; public static boolean keepImagesOpen = true; public static boolean iterativeRelocalization = true; public static String[] localization = { "None", "3-dimensional quadratic fit (all detections)", "Gauss fit (true correspondences)", "Gauss fit (all detections)" }; public static String[] beadBrightness = { "Very weak", "Weak", "Comparable to Sample", "Strong", "Advanced ...", "Interactive ..." }; public static int defaultBeadBrightness = 1; public static boolean overrideResolution = false; public static double xyRes = 0.73; public static double zRes = 2; final String model[] = new String[] { "Translation", "Rigid", "Affine" }; public static int defaultModel = 2; public static boolean loadRegistration = false; public static boolean timeLapseRegistration = false; final String timeLapseRegistrationTypes[] = new String[] { "Manually (interactive)", "Manually (specify)", "Automatically" }; public static int defaultTimeLapseRegistration = 0; public static int defaultTimePoint = 1; private SPIMConfiguration conf; public SPIMConfiguration singleChannel( final int choiceType ) // 0 == DoG, 1 = IntegralImage { conf = null; final GenericDialogPlus gd = new GenericDialogPlus( "Single Channel Bead-based Registration" ); gd.addDirectoryOrFileField( "SPIM_data_directory", spimDataDirectory ); final TextField tfSpimDataDirectory = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Pattern_of_SPIM files", fileNamePattern, 25 ); final TextField tfFilePattern = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Timepoints_to_process", timepoints ); final TextField tfTimepoints = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Angles_to_process", angles ); final TextField tfAngles = (TextField) gd.getStringFields().lastElement(); gd.addMessage( "" ); gd.addCheckbox( "Load_segmented_beads", loadSegmentation ); gd.addChoice( "Bead_brightness", beadBrightness, beadBrightness[ defaultBeadBrightness ] ); gd.addChoice( "Subpixel_localization", localization, localization[ relocalize ] ); gd.addCheckbox( "Specify_calibration_manually (Note: otherwise read from file - slow)", overrideResolution ); final Checkbox dimensionsBox = (Checkbox)gd.getCheckboxes().lastElement(); gd.addNumericField( "xy_resolution (um/px)", xyRes, 3 ); final TextField tfXyRes = (TextField) gd.getNumericFields().lastElement(); gd.addNumericField( "z_resolution (um/px)", zRes, 3 ); final TextField tfZRes = (TextField) gd.getNumericFields().lastElement(); gd.addMessage( "" ); gd.addChoice( "Transformation_model", model, model[ defaultModel ] ); gd.addCheckbox( "Re-use_per_timepoint_registration", loadRegistration ); gd.addMessage( "" ); gd.addCheckbox( "Timelapse_registration", timeLapseRegistration ); gd.addChoice( "Select_reference timepoint", timeLapseRegistrationTypes, timeLapseRegistrationTypes[ defaultTimeLapseRegistration ] ); gd.addMessage( "" ); gd.addChoice( "ImgLib_container", Multi_View_Deconvolution.imglibContainer, Multi_View_Deconvolution.imglibContainer[ Multi_View_Deconvolution.defaultContainerInput ] ); gd.addMessage(""); gd.addMessage("This Plugin is developed by Stephan Preibisch\n" + myURL); MultiLineLabel text = (MultiLineLabel) gd.getMessage(); GUIHelper.addHyperLinkListener(text, myURL); gd.addDialogListener( new DialogListener() { @Override public boolean dialogItemChanged( GenericDialog dialog, AWTEvent e ) { if ( e == null ) { if ( !gd.wasCanceled() ) { conf = getConfigurationSingleChannel( dialog, choiceType ); } return true; } if ( e instanceof TextEvent && e.getID() == TextEvent.TEXT_VALUE_CHANGED && e.getSource() == tfSpimDataDirectory ) { TextField tf = ( TextField ) e.getSource(); spimDataDirectory = tf.getText(); File f = new File( spimDataDirectory ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { SPIMExperiment exp = new SPIMExperiment( f.getAbsolutePath() ); // disable file pattern field tfFilePattern.setEnabled( false ); // set timepoint string String expTimepoints = ""; if ( exp.timepointStart == exp.timepointEnd ) expTimepoints = "" + exp.timepointStart; else expTimepoints = "" + exp.timepointStart + "-" + exp.timepointEnd; tfTimepoints.setText( expTimepoints ); // set angles string String expAngles = ""; for ( String angle : exp.angles ) { int a = Integer.parseInt( angle.substring( 1, angle.length() ) ); if ( !expAngles.equals( "" ) ) expAngles += ","; expAngles += a; } tfAngles.setText( expAngles ); // set dimension fields if ( exp.pw != exp.ph ) IJ.log( "Warning: pixel width != pixel height in " + spimDataDirectory ); dimensionsBox.setState( true ); tfXyRes.setText( String.format( "%.3f", exp.pw ) ); tfZRes.setText( String.format( "%.3f", exp.pd ) ); } else { // enable file pattern field tfFilePattern.setEnabled( true ); } } return true; } } ); System.out.println( "init Bead_Registration dialog: tfSpimDataDirectory.getText() = " + tfSpimDataDirectory.getText() ); File f = new File( tfSpimDataDirectory.getText() ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { // disable file pattern field tfFilePattern.setEnabled( false ); } gd.showDialog(); if ( gd.wasCanceled() || conf == null ) return null; return conf; } private static SPIMConfiguration getConfigurationSingleChannel( final GenericDialog gd, final int choiceType ) // 0 == DoG, 1 = IntegralImage { spimDataDirectory = gd.getNextString(); fileNamePattern = gd.getNextString(); timepoints = gd.getNextString(); angles = gd.getNextString(); loadSegmentation = gd.getNextBoolean(); defaultBeadBrightness = gd.getNextChoiceIndex(); relocalize = gd.getNextChoiceIndex(); overrideResolution = gd.getNextBoolean(); xyRes = gd.getNextNumber(); zRes = gd.getNextNumber(); defaultModel = gd.getNextChoiceIndex(); loadRegistration = gd.getNextBoolean(); timeLapseRegistration = gd.getNextBoolean(); defaultTimeLapseRegistration = gd.getNextChoiceIndex(); Multi_View_Deconvolution.defaultContainerInput = gd.getNextChoiceIndex(); SPIMConfiguration conf = new SPIMConfiguration(); if ( Multi_View_Deconvolution.defaultContainerInput == 1 ) conf.inputImageFactory = new CellContainerFactory( 256 ); else conf.inputImageFactory = new ArrayContainerFactory(); if ( conf.initialSigma == null || conf.initialSigma.length != 1 || conf.minPeakValue == null || conf.minPeakValue.length != 1 ) { conf.initialSigma = new float[]{ 1.8f }; conf.minPeakValue = new float[]{ 0.01f }; } if ( conf.integralImgRadius1 == null || conf.integralImgRadius2 == null || conf.integralImgThreshold == null || conf.integralImgRadius1.length != 1 || conf.integralImgRadius2.length != 1 || conf.integralImgThreshold.length != 1 ) { conf.integralImgRadius1 = new int[]{ 3 }; conf.integralImgRadius2 = new int[]{ 5 }; conf.integralImgThreshold = new float[]{ 0.1f }; } if ( !loadSegmentation ) { if ( defaultBeadBrightness == 0 ) { conf.minPeakValue[ 0 ] = 0.001f; conf.integralImgThreshold[ 0 ] = 0.0025f; } else if ( defaultBeadBrightness == 1 ) { conf.minPeakValue[ 0 ] = 0.008f; conf.integralImgThreshold[ 0 ] = 0.02f; } else if ( defaultBeadBrightness == 2 ) { conf.minPeakValue[ 0 ] = 0.03f; conf.integralImgThreshold[ 0 ] = 0.075f; } else if ( defaultBeadBrightness == 3 ) { conf.minPeakValue[ 0 ] = 0.1f; conf.integralImgThreshold[ 0 ] = 0.25f; } else { // open advanced bead brightness detection final double[] values; if ( defaultBeadBrightness == 4 ) { if ( choiceType == 0 ) values = getAdvancedDoGParameters( new int[ 1 ] )[ 0 ]; else values = getAdvancedIntegralImageParameters( new int[ 1 ] )[ 0 ]; } else { if ( choiceType == 0 ) { values = new double[]{ conf.initialSigma[ 0 ], conf.minPeakValue[ 0 ] }; getInteractiveDoGParameters( "Select view to analyze", values ); IJ.log( "sigma1 = " + values[ 0 ] ); IJ.log( "threshold = " + values[ 1 ] ); } else { if ( defaultintegralParameters != null && defaultIntegralRadius != null && defaultintegralParameters.length >= 1 ) values = new double[]{ defaultIntegralRadius[ 0 ][ 0 ], defaultIntegralRadius[ 0 ][ 1 ], defaultintegralParameters[ 0 ] }; else values = new double[]{ conf.integralImgRadius1[ 0 ], conf.integralImgRadius2[ 0 ], conf.integralImgThreshold[ 0 ] }; getInteractiveIntegralParameters( "Select view to analyze", values ); defaultIntegralRadius = new int[ 1 ][ 2 ]; defaultintegralParameters = new double[ 1 ]; defaultIntegralRadius[ 0 ][ 0 ] = (int)Math.round( values[ 0 ] ); defaultIntegralRadius[ 0 ][ 1 ] = (int)Math.round( values[ 1 ] ); defaultintegralParameters[ 0 ] = values[ 2 ]; IJ.log( "r1 = " + values[ 0 ] ); IJ.log( "r2 = " + values[ 1 ] ); IJ.log( "threshold = " + values[ 2 ] ); } } // cancelled if ( values == null ) return null; if ( choiceType == 0 ) { conf.initialSigma[ 0 ] = (float)values[ 0 ]; conf.minPeakValue[ 0 ] = (float)values[ 1 ]; } else { conf.integralImgRadius1[ 0 ] = (int)Math.round( values[ 0 ] ); conf.integralImgRadius2[ 0 ] = (int)Math.round( values[ 1 ] ); conf.integralImgThreshold[ 0 ] = (float)values[ 2 ]; } } } if ( choiceType == 1 ) conf.segmentation = SegmentationTypes.DOM; conf.minInitialPeakValue = new float[]{ conf.minPeakValue[ 0 ]/4 }; conf.timepointPattern = timepoints; conf.channelPattern = ""; conf.channelsToRegister = ""; conf.channelsToFuse = ""; conf.anglePattern = angles; conf.inputFilePattern = fileNamePattern; File f = new File( spimDataDirectory ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { conf.spimExperiment = new SPIMExperiment( f.getAbsolutePath() ); conf.inputdirectory = f.getAbsolutePath().substring( 0, f.getAbsolutePath().length() - 4 ); System.out.println( "inputdirectory : " + conf.inputdirectory ); } else { conf.inputdirectory = spimDataDirectory; } conf.overrideImageZStretching = overrideResolution; conf.doFit = relocalize; if ( conf.doFit == 2 ) { GenericDialog gdGauss = new GenericDialog( "Gauss options" ); gdGauss.addMessage( "The re-localization using a Gaussian fit will be done for the true corresponding " + "beads only, performed after or iteratively with the registration." ); gdGauss.addCheckbox( "Keep_images_open", keepImagesOpen ); gdGauss.showDialog(); if ( gdGauss.wasCanceled() ) return null; conf.doGaussKeepImagesOpen = keepImagesOpen = gdGauss.getNextBoolean(); } if ( defaultTimeLapseRegistration == 1 ) { GenericDialog gdTL = new GenericDialog( "Select reference timepoint" ); gdTL.addNumericField( "Reference_timepoint", defaultTimePoint, 0 ); gdTL.showDialog(); if ( gdTL.wasCanceled() ) return null; defaultTimePoint = (int)Math.round( gdTL.getNextNumber() ); } if ( overrideResolution ) conf.zStretching = zRes / xyRes; conf.readSegmentation = loadSegmentation; conf.readRegistration = loadRegistration; if ( defaultModel == 0 ) { conf.transformationModel = "Translation"; conf.max_epsilon = 10; conf.numIterations = 10000; } else if ( defaultModel == 1 ) { conf.transformationModel = "Rigid"; conf.max_epsilon = 7; conf.numIterations = 10000; } else { conf.transformationModel = "Affine"; } conf.registerOnly = true; conf.timeLapseRegistration = timeLapseRegistration; return conf; } public static String fileNamePatternMC = "spim_TL{t}_Channel{c}_Angle{a}.lsm"; public static String channelsBeadsMC = "0, 1"; public static int[] defaultBeadBrightnessMC = null; public SPIMConfiguration multiChannel( final int choiceType ) // 0 == DoG, 1 = IntegralImage { conf = null; // The first main dialog final GenericDialogPlus gd = new GenericDialogPlus( "Multi Channel Bead-based Registration" ); gd.addDirectoryOrFileField( "SPIM_data_directory", spimDataDirectory ); final TextField tfSpimDataDirectory = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Pattern_of_SPIM files", fileNamePatternMC, 25 ); final TextField tfFilePattern = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Timepoints_to_process", timepoints ); final TextField tfTimepoints = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Channels_containing_beads", channelsBeadsMC ); final TextField tfBeadChannels = (TextField) gd.getStringFields().lastElement(); gd.addStringField( "Angles to process", angles ); final TextField tfAngles = (TextField) gd.getStringFields().lastElement(); //gd.addCheckbox( "Process_angles_simultaneously (needs lots of RAM)", processAnglesSimultaneously ); gd.addMessage( "" ); gd.addCheckbox( "Re-use_segmented_beads", loadSegmentation ); gd.addCheckbox( "Override_file_dimensions", overrideResolution ); final Checkbox dimensionsBox = (Checkbox)gd.getCheckboxes().lastElement(); gd.addNumericField( "xy_resolution (um/px)", xyRes, 3 ); final TextField tfXyRes = (TextField) gd.getNumericFields().lastElement(); gd.addNumericField( "z_resolution (um/px)", zRes, 3 ); final TextField tfZRes = (TextField) gd.getNumericFields().lastElement(); gd.addMessage( "" ); gd.addChoice( "Transformation_model", model, model[ defaultModel ] ); gd.addCheckbox( "Re-use_per_timepoint_registration", loadRegistration ); gd.addMessage( "" ); gd.addCheckbox( "Timelapse_registration", timeLapseRegistration ); gd.addChoice( "Select_reference timepoint", timeLapseRegistrationTypes, timeLapseRegistrationTypes[ defaultTimeLapseRegistration ] ); gd.addMessage( "" ); gd.addChoice( "ImgLib_container", Multi_View_Deconvolution.imglibContainer, Multi_View_Deconvolution.imglibContainer[ Multi_View_Deconvolution.defaultContainerInput ] ); gd.addMessage(""); gd.addMessage("This Plugin is developed by Stephan Preibisch\n" + myURL); final MultiLineLabel text = (MultiLineLabel) gd.getMessage(); GUIHelper.addHyperLinkListener(text, myURL); gd.addDialogListener( new DialogListener() { @Override public boolean dialogItemChanged( final GenericDialog dialog, final AWTEvent e ) { if ( e == null ) { if ( !gd.wasCanceled() ) { conf = getConfigurationMultiChannel( dialog ); } return true; } if ( e instanceof TextEvent && e.getID() == TextEvent.TEXT_VALUE_CHANGED && e.getSource() == tfSpimDataDirectory ) { final TextField tf = ( TextField ) e.getSource(); spimDataDirectory = tf.getText(); final File f = new File( spimDataDirectory ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { final SPIMExperiment exp = new SPIMExperiment( f.getAbsolutePath() ); // disable file pattern field tfFilePattern.setEnabled( false ); // set timepoint string String expTimepoints = ""; if ( exp.timepointStart == exp.timepointEnd ) expTimepoints = "" + exp.timepointStart; else expTimepoints = "" + exp.timepointStart + "-" + exp.timepointEnd; tfTimepoints.setText( expTimepoints ); // set channels string String expChannels = ""; for ( final String channel : exp.channels ) { final int c = Integer.parseInt( channel.substring( 1, channel.length() ) ); if ( !expChannels.equals( "" ) ) expChannels += ","; expChannels += c; } tfBeadChannels.setText( expChannels ); // set angles string String expAngles = ""; for ( final String angle : exp.angles ) { final int a = Integer.parseInt( angle.substring( 1, angle.length() ) ); if ( !expAngles.equals( "" ) ) expAngles += ","; expAngles += a; } tfAngles.setText( expAngles ); // set dimension fields if ( exp.pw != exp.ph ) IJ.log( "Warning: pixel width != pixel height in " + spimDataDirectory ); dimensionsBox.setState( true ); tfXyRes.setText( String.format( "%.3f", exp.pw ) ); tfZRes.setText( String.format( "%.3f", exp.pd ) ); } else { // enable file pattern field tfFilePattern.setEnabled( true ); } } return true; } } ); System.out.println( "init Bead_Registration dialog: tfSpimDataDirectory.getText() = " + tfSpimDataDirectory.getText() ); final File f = new File( tfSpimDataDirectory.getText() ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { // disable file pattern field tfFilePattern.setEnabled( false ); } gd.showDialog(); if ( gd.wasCanceled() ) return null; return conf; } private static SPIMConfiguration getConfigurationMultiChannel( final GenericDialog gd ) { spimDataDirectory = gd.getNextString(); fileNamePatternMC = gd.getNextString(); timepoints = gd.getNextString(); channelsBeadsMC = gd.getNextString(); angles = gd.getNextString(); //processAnglesSimultaneously = gd.getNextBoolean(); loadSegmentation = gd.getNextBoolean(); overrideResolution = gd.getNextBoolean(); xyRes = gd.getNextNumber(); zRes = gd.getNextNumber(); defaultModel = gd.getNextChoiceIndex(); loadRegistration = gd.getNextBoolean(); timeLapseRegistration = gd.getNextBoolean(); defaultTimeLapseRegistration = gd.getNextChoiceIndex(); Multi_View_Deconvolution.defaultContainerInput = gd.getNextChoiceIndex(); // check if channels are more or less ok int numChannels = 0; ArrayList<Integer> channels; try { channels = SPIMConfiguration.parseIntegerString( channelsBeadsMC ); numChannels = channels.size(); } catch (ConfigurationParserException e) { IOFunctions.printErr( "Cannot understand/parse the channels: " + channelsBeadsMC ); return null; } if ( numChannels < 1 ) { IOFunctions.printErr( "There are no channels given: " + channelsBeadsMC ); return null; } // create the configuration object final SPIMConfiguration conf = new SPIMConfiguration(); if ( Multi_View_Deconvolution.defaultContainerInput == 1 ) conf.inputImageFactory = new CellContainerFactory( 256 ); else conf.inputImageFactory = new ArrayContainerFactory(); if ( conf.initialSigma == null || conf.initialSigma.length != numChannels ) { conf.initialSigma = new float[ numChannels ]; for ( int c = 0; c < numChannels; ++c ) conf.initialSigma[ c ] = 1.8f; } if ( conf.minPeakValue == null || conf.minPeakValue.length != numChannels ) { conf.minPeakValue = new float[ numChannels ]; for ( int c = 0; c < numChannels; ++c ) conf.minPeakValue[ c ] = 0.01f; } if ( conf.minInitialPeakValue == null || conf.minInitialPeakValue.length != numChannels ) { conf.minInitialPeakValue = new float[ numChannels ]; for ( int c = 0; c < numChannels; ++c ) conf.minInitialPeakValue[ c ] = conf.minPeakValue[ c ] / 4; } // if not segmentation and registration are loaded ask the parameters // individually for each channel if ( !loadSegmentation && !loadRegistration ) { if ( defaultBeadBrightnessMC == null || defaultBeadBrightness != numChannels ) { defaultBeadBrightnessMC = new int[ numChannels ]; for ( int c = 0; c < numChannels; ++c ) defaultBeadBrightnessMC[ c ] = 1; } final GenericDialogPlus gd2 = new GenericDialogPlus( "Bead Brightness for Multi Channel Registration" ); for ( int c = 0; c < numChannels; ++c ) gd2.addChoice( "Bead_brightness_channel_" + channels.get( c ), beadBrightness, beadBrightness[ defaultBeadBrightnessMC[ c ] ] ); gd2.showDialog(); if ( gd2.wasCanceled() ) return null; int advanced = 0; int interactive = 0; for ( int c = 0; c < numChannels; ++c ) { defaultBeadBrightnessMC[ c ] = gd2.getNextChoiceIndex(); if ( defaultBeadBrightnessMC[ c ] == 0 ) conf.minPeakValue[ c ] = 0.001f; else if ( defaultBeadBrightnessMC[ c ] == 1 ) conf.minPeakValue[ c ] = 0.008f; else if ( defaultBeadBrightnessMC[ c ] == 2 ) conf.minPeakValue[ c ] = 0.03f; else if ( defaultBeadBrightnessMC[ c ] == 3 ) conf.minPeakValue[ c ] = 0.1f; else if ( defaultBeadBrightnessMC[ c ] == 4 ) advanced++; else interactive++; } // get the interactive values for all channels if ( interactive > 0 ) for ( int c = 0; c < numChannels; ++c ) if ( defaultBeadBrightnessMC[ c ] == 5 ) { final double[] values = new double[] { conf.initialSigma[ c ], conf.minPeakValue[ c ] }; getInteractiveDoGParameters( "Select view to analyze for channel " + channels.get( c ), values ); conf.initialSigma[ c ] = (float)values[ 0 ]; conf.minPeakValue[ c ] = (float)values[ 1 ]; } // get the advanced values for all channels if ( advanced > 0 ) { final int channelIndices[] = new int[ advanced ]; int count = 0; // do all advanced parameters in one dialog for ( int c = 0; c < numChannels; ++c ) if ( defaultBeadBrightnessMC[ c ] == 4 ) channelIndices[ count++ ] = channels.get( c ); final double[][] values = getAdvancedDoGParameters( channelIndices ); // write them to the configuration count = 0; for ( int c = 0; c < numChannels; ++c ) if ( defaultBeadBrightnessMC[ c ] == 4 ) { conf.initialSigma[ c ] = (float)values[ count ][ 0 ]; conf.minPeakValue[ c ] = (float)values[ count++ ][ 1 ]; } } } for ( int c = 0; c < numChannels; ++c ) conf.minInitialPeakValue[ c ] = conf.minPeakValue[ c ] / 4; conf.timepointPattern = timepoints; conf.anglePattern = angles; conf.channelPattern = channelsBeadsMC; conf.channelsToRegister = channelsBeadsMC; conf.channelsToFuse = ""; conf.inputFilePattern = fileNamePatternMC; final File f = new File( spimDataDirectory ); if ( f.exists() && f.isFile() && f.getName().endsWith( ".xml" ) ) { conf.spimExperiment = new SPIMExperiment( f.getAbsolutePath() ); conf.inputdirectory = f.getAbsolutePath().substring( 0, f.getAbsolutePath().length() - 4 ); System.out.println( "inputdirectory : " + conf.inputdirectory ); } else { conf.inputdirectory = spimDataDirectory; } if ( defaultTimeLapseRegistration == 1 ) { GenericDialog gdTL = new GenericDialog( "Select reference timepoint" ); gdTL.addNumericField( "Reference_timepoint", defaultTimePoint, 0 ); gdTL.showDialog(); if ( gdTL.wasCanceled() ) return null; defaultTimePoint = (int)Math.round( gdTL.getNextNumber() ); } conf.overrideImageZStretching = overrideResolution; if ( overrideResolution ) conf.zStretching = zRes / xyRes; conf.readSegmentation = loadSegmentation; conf.readRegistration = loadRegistration; if ( defaultModel == 0 ) { conf.transformationModel = "Translation"; conf.max_epsilon = 10; conf.numIterations = 10000; } else if ( defaultModel == 1 ) { conf.transformationModel = "Rigid"; conf.max_epsilon = 7; conf.numIterations = 10000; } else { conf.transformationModel = "Affine"; } conf.registerOnly = true; conf.timeLapseRegistration = timeLapseRegistration; return conf; } static double[][] defaultDoGParameters = null; //[channel][sigma, threshold] public static double[][] getAdvancedDoGParameters( final int[] channelIndices ) { if ( channelIndices == null || channelIndices.length == 0 ) return null; if ( defaultDoGParameters == null || defaultDoGParameters.length != channelIndices.length ) { defaultDoGParameters = new double[ channelIndices.length ][ 2 ]; for ( final double dog[] : defaultDoGParameters ) { dog[ 0 ] = 1.8; dog[ 1 ] = 0.008; } } final GenericDialog gd1 = new GenericDialog( "Select Difference-of-Gaussian Parameters" ); for ( int i = 0; i < channelIndices.length; ++i ) { final int channel = channelIndices[ i ]; gd1.addNumericField( "Channel_" + channel + "_Initial_sigma", defaultDoGParameters[ i ][ 0 ], 4 ); gd1.addNumericField( "Channel_" + channel + "_Threshold", defaultDoGParameters[ i ][ 1 ], 4 ); } gd1.showDialog(); if ( gd1.wasCanceled() ) return null; for ( int i = 0; i < channelIndices.length; ++i ) { defaultDoGParameters[ i ][ 0 ] = gd1.getNextNumber(); defaultDoGParameters[ i ][ 1 ] = gd1.getNextNumber(); } return defaultDoGParameters.clone(); } static double[] defaultintegralParameters = null;//channel[threshold] static int[][] defaultIntegralRadius = null;//channel[r1, r2, threshold] public static double[][] getAdvancedIntegralImageParameters( final int[] channelIndices ) { if ( channelIndices == null || channelIndices.length == 0 ) return null; if ( defaultintegralParameters == null || defaultintegralParameters.length != channelIndices.length || defaultIntegralRadius == null || defaultIntegralRadius.length != channelIndices.length ) { defaultintegralParameters = new double[ channelIndices.length ]; defaultIntegralRadius = new int[ channelIndices.length ][ 2 ]; for ( int i = 0; i < channelIndices.length; ++i ) { defaultintegralParameters[ i ] = 0.02; defaultIntegralRadius[ i ][ 0 ] = 2; // r=3 defaultIntegralRadius[ i ][ 1 ] = 3; // r=5 } } final GenericDialog gd = new GenericDialog( "Select Integral Image Parameters" ); for ( int i = 0; i < channelIndices.length; ++i ) { final int channel = channelIndices[ i ]; gd.addNumericField( "Channel_" + channel + "_radius_1", defaultIntegralRadius[ i ][ 0 ], 0 ); gd.addNumericField( "Channel_" + channel + "_radius_2", defaultIntegralRadius[ i ][ 1 ], 0 ); gd.addNumericField( "Channel_" + channel + "_Threshold", defaultintegralParameters[ i ], 4 ); } gd.showDialog(); if ( gd.wasCanceled() ) return null; final double[][] integralParameters = new double[ channelIndices.length ][ 3 ]; for ( int i = 0; i < channelIndices.length; ++i ) { defaultIntegralRadius[ i ][ 0 ] = (int)Math.round( gd.getNextNumber() ); defaultIntegralRadius[ i ][ 1 ] = (int)Math.round( gd.getNextNumber() ); defaultintegralParameters[ i ] = gd.getNextNumber(); if ( defaultIntegralRadius[ i ][ 0 ] < 1 ) defaultIntegralRadius[ i ][ 0 ] = 1; if ( defaultIntegralRadius[ i ][ 1 ] < defaultIntegralRadius[ i ][ 0 ] ) defaultIntegralRadius[ i ][ 1 ] = defaultIntegralRadius[ i ][ 0 ] + 1; if ( defaultintegralParameters[ i ] <= 0 ) defaultintegralParameters[ i ] = Float.MIN_VALUE; integralParameters[ i ][ 0 ] = defaultIntegralRadius[ i ][ 0 ]; integralParameters[ i ][ 1 ] = defaultIntegralRadius[ i ][ 1 ]; integralParameters[ i ][ 2 ] = defaultintegralParameters[ i ]; } return integralParameters; } /** * Can be called with values[ 3 ], i.e. [initialsigma, sigma2, threshold] or * values[ 2 ], i.e. [initialsigma, threshold] * * The results are stored in the same array. * If called with values[ 2 ], sigma2 changing will be disabled * * @param text - the text which is shown when asking for the file * @param values - the intial values and also contains the result */ public static void getInteractiveDoGParameters( final String text, final double values[] ) { final GenericDialogPlus gd = new GenericDialogPlus( text ); gd.addFileField( "", spimDataDirectory, 50 ); gd.showDialog(); if ( gd.wasCanceled() ) return; final String file = gd.getNextString(); IOFunctions.println( "Loading " + file ); final Image<FloatType> img = LOCI.openLOCIFloatType( file, new ArrayContainerFactory() ); if ( img == null ) { IOFunctions.println( "File not found: " + file ); return; } img.getDisplay().setMinMax(); final ImagePlus imp = ImageJFunctions.copyToImagePlus( img ); img.close(); imp.show(); imp.setSlice( imp.getStackSize() / 2 ); imp.setRoi( 0, 0, imp.getWidth()/3, imp.getHeight()/3 ); final InteractiveDoG idog = new InteractiveDoG(); if ( values.length == 2 ) { idog.setSigma2isAdjustable( false ); idog.setInitialSigma( (float)values[ 0 ] ); idog.setThreshold( (float)values[ 1 ] ); } else { idog.setInitialSigma( (float)values[ 0 ] ); idog.setThreshold( (float)values[ 2 ] ); } idog.run( null ); while ( !idog.isFinished() ) SimpleMultiThreading.threadWait( 100 ); imp.close(); if ( values.length == 2) { values[ 0 ] = idog.getInitialSigma(); values[ 1 ] = idog.getThreshold(); } else { values[ 0 ] = idog.getInitialSigma(); values[ 1 ] = idog.getSigma2(); values[ 2 ] = idog.getThreshold(); } } /** * Can be called with values[ 3 ], i.e. [r1, r2, threshold] (r2 is only written as result) * * The results are stored in the same array. * * @param text - the text which is shown when asking for the file * @param values - the intial values and also contains the result */ public static void getInteractiveIntegralParameters( final String text, final double values[] ) { final GenericDialogPlus gd = new GenericDialogPlus( text ); gd.addFileField( "", spimDataDirectory, 50 ); gd.showDialog(); if ( gd.wasCanceled() ) return; final String file = gd.getNextString(); IOFunctions.println( "Loading " + file ); final Image<FloatType> img = LOCI.openLOCIFloatType( file, new ArrayContainerFactory() ); if ( img == null ) { IOFunctions.println( "File not found: " + file ); return; } img.getDisplay().setMinMax(); final ImagePlus imp = ImageJFunctions.copyToImagePlus( img ); img.close(); imp.show(); imp.setSlice( imp.getStackSize() / 2 ); final InteractiveIntegral ii = new InteractiveIntegral(); ii.setInitialRadius( Math.round( (float)values[ 0 ] ) ); ii.setThreshold( (float)values[ 2 ] ); ii.run( null ); while ( !ii.isFinished() ) SimpleMultiThreading.threadWait( 100 ); imp.close(); values[ 0 ] = ii.getRadius1(); values[ 1 ] = ii.getRadius2(); values[ 2 ] = ii.getThreshold(); } protected static boolean init( final SPIMConfiguration conf ) { // check the directory string conf.inputdirectory = conf.inputdirectory.replace('\\', '/'); conf.inputdirectory = conf.inputdirectory.replaceAll( "//", "/" ); conf.inputdirectory = conf.inputdirectory.trim(); if (conf.inputdirectory.length() > 0 && !conf.inputdirectory.endsWith("/")) conf.inputdirectory = conf.inputdirectory + "/"; conf.outputdirectory = conf.inputdirectory + "output/"; conf.registrationFiledirectory = conf.inputdirectory + "registration/"; // variable specific verification if (conf.numberOfThreads < 1) conf.numberOfThreads = Threads.numThreads(); if (conf.scaleSpaceNumberOfThreads < 1) conf.scaleSpaceNumberOfThreads = Threads.numThreads(); try { if ( conf.isHuiskenFormat() ) conf.getFilenamesHuisken(); else conf.getFileNames(); } catch ( ConfigurationParserException e ) { IJ.error( "Cannot parse input: " + e ); return false; } // set interpolator stuff conf.interpolatorFactorOutput.setOutOfBoundsStrategyFactory( conf.strategyFactoryOutput ); // check if directories exist File dir = new File(conf.outputdirectory, ""); if (!dir.exists()) { IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Creating directory '" + conf.outputdirectory + "'."); boolean success = dir.mkdirs(); if (!success) { if (!dir.exists()) { IOFunctions.printErr("(" + new Date(System.currentTimeMillis()) + "): Cannot create directory '" + conf.outputdirectory + "', quitting."); return false; } } } dir = new File(conf.registrationFiledirectory, ""); if (!dir.exists()) { IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Creating directory '" + conf.registrationFiledirectory + "'."); boolean success = dir.mkdirs(); if (!success) { if (!dir.exists()) { IOFunctions.printErr("(" + new Date(System.currentTimeMillis()) + "): Cannot create directory '" + conf.registrationFiledirectory + "', quitting."); return false; } } } return true; } public static final void addHyperLinkListener( final MultiLineLabel text, final String myURL ) { GUIHelper.addHyperLinkListener( text, myURL ); } public static void main(String[] args) { Debug.run("Record...", null); Debug.run("Find Commands...", null); Debug.run("Bead-based registration", null); } }