/*-
* #%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 mpicbg.spim.io;
import fiji.plugin.Multi_View_Deconvolution;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import mpicbg.imglib.container.ContainerFactory;
import mpicbg.imglib.container.array.ArrayContainerFactory;
import mpicbg.imglib.interpolation.InterpolatorFactory;
import mpicbg.imglib.interpolation.linear.LinearInterpolatorFactory;
import mpicbg.imglib.outofbounds.OutOfBoundsStrategyFactory;
import mpicbg.imglib.outofbounds.OutOfBoundsStrategyMirrorFactory;
import mpicbg.imglib.outofbounds.OutOfBoundsStrategyValueFactory;
import mpicbg.imglib.type.numeric.real.FloatType;
import mpicbg.imglib.util.Util;
import mpicbg.models.AbstractAffineModel3D;
import mpicbg.models.AffineModel3D;
import mpicbg.models.RigidModel3D;
import mpicbg.models.TranslationModel3D;
import mpicbg.spim.registration.ViewStructure;
import spimopener.SPIMExperiment;
public class SPIMConfiguration
{
public enum SegmentationTypes { THRESHOLD, DOG, DOM };
// general
public String timepointPattern;
public int timepoints[];
public String anglePattern;
public int angles[];
public int illuminations[];
//public String angleString;
public String inputFilePattern;//spim_TL{i}_Angle\d*\.lsm
public int[] channels, channelsRegister, channelsFuse;
public int[][] channelsMirror;
public String channelPattern;
public String channelsToRegister;
public String channelsToFuse;
public String mirrorChannels = "";
public int[] registrationAssignmentForFusion = null;
// [timepoint][channel][angle][illumination]
public File file[][][][];
public String inputdirectory;
public String outputdirectory;// = "";
public String registrationFiledirectory;// = "";
public String debugLevel;
public int debugLevelInt = ViewStructure.DEBUG_MAIN;
public boolean showImageJWindow = false;
public boolean collectRegistrationStatistics = false;
public String transformationModel = "Affine";
// time lapse
public boolean timeLapseRegistration = false;
public boolean fuseReferenceTimepoint = true;
public int referenceTimePoint = 1;
public SPIMExperiment spimExperiment = null;
// image factories
public ContainerFactory inputImageFactory = new ArrayContainerFactory();
public ContainerFactory processImageFactory = new ArrayContainerFactory();
// for cached image arrays
public String tempDir = null;
// for the interpolation
public OutOfBoundsStrategyFactory<FloatType> strategyFactoryOutput = new OutOfBoundsStrategyValueFactory<FloatType>();
public InterpolatorFactory<FloatType> interpolatorFactorOutput = new LinearInterpolatorFactory<FloatType>( strategyFactoryOutput );
// outofbounds strategy factories
public OutOfBoundsStrategyFactory<FloatType> strategyFactoryGauss = new OutOfBoundsStrategyMirrorFactory<FloatType>();
// segmentation
public int writeOutputImage = 1;
public boolean showOutputImage = false;
// which fusion weightening
public boolean useEntropy = false;
public boolean useIntegralContentBased = false;
public boolean useGaussContentBased = false;
public boolean useLinearBlening = true;
public boolean paralellFusion = true;
public boolean sequentialFusion = false;
public int numParalellViews = 1;
public boolean multipleImageFusion = false;
public boolean isDeconvolution = false;
public boolean deconvolutionLoadSequentially = false;
public boolean deconvolutionJustShowOverlap = false;
public int deconvolutionDisplayPSF = 1;
public boolean extractPSF = true;
public boolean transformPSFs = true;
public ArrayList< String > psfFiles = null;
public Multi_View_Deconvolution instance = null;
public boolean fuseOnly = false;
public boolean registerOnly = false;
public boolean readSegmentation = false;
public boolean writeSegmentation = true;
public boolean readRegistration = false;
public boolean writeRegistration = true;
public boolean overrideImageZStretching = false;
public double zStretching = 1;
public int background = 0;
// re-localize true correspondences with a gauss fit?
// 0 == no, 1 == quadratic fit, 2 == only correspondences gauss, 3 == all detections gauss
public int doFit = 0;
public boolean doGaussKeepImagesOpen = false;
// by default we do a DoG
public SegmentationTypes segmentation = SegmentationTypes.DOG;
// threshold segmentation
public float threshold = 0.9f;
public float fixedThreshold = 0.02f;
public boolean useFixedThreshold = false;
public double circularityFactor = 0.5;
public int minBlackBorder = 1;
public int minSize = 10;
public int maxSize = 15 * 15 * 15;
public boolean useCenterOfMass = false;
// ScaleSpace Segmentation
public float[] minPeakValue = new float[]{ 0.01f };
public float[] minInitialPeakValue = null; // minPeakValue/10
public float identityRadius = 3f;
public float maximaTolerance = 0.01f;
public float imageSigma = 0.5f;
public float[] initialSigma = new float[]{ 1.8f };
public int stepsPerOctave = 4;
public int steps = 3;
public boolean detectSmallestStructures = false;
public int scaleSpaceNumberOfThreads = 0;
// Integral image parameters
public int[] integralImgRadius1 = new int[]{ 2 };
public int[] integralImgRadius2 = new int[]{ 3 };
public float[] integralImgThreshold = new float[]{ 0.02f };
// PointDescriptor properties
public double differenceThreshold = 50;
public double ratioOfDistance = 10;
public int neighbors = 3;
public boolean useAssociatedBeads = false;
public boolean useRANSAC = true;
// RANSAC
public float max_epsilon = 5;
public float min_inlier_ratio = 0.1f;
public int numIterations = 1000;
// output image
public int scale = 1;
public int cropOffsetX = 0;
public int cropOffsetY = 0;
public int cropOffsetZ = 0;
public int cropSizeX = 0;
public int cropSizeY = 0;
public int cropSizeZ = 0;
public int numberOfThreads = 0;
// defines the sigma of the volumes injected
public float sigma = 0.25f;
// where the injected Gaussian Distributions are cut off
public int cutOffRadiusGauss = 2;
// the number of histogram bins for computing the entropy
public int histogramBins = 256;
// the window Sizes for computing the local entropy
public int windowSizeX = 19;
public int windowSizeY = 19;
// linear blending
public float alpha = 1.5f;
// gauss fusion
public float fusionSigma1 = 20;//42;
public float fusionSigma2 = 40;//88;
public AbstractAffineModel3D getModel()
{
if ( transformationModel.equals( "Translation" ) )
return new TranslationModel3D();
else if ( transformationModel.equals( "Rigid" ) )
return new RigidModel3D();
else
return new AffineModel3D();
}
public int getIndexForTimePoint( final int timepoint )
{
for ( int i = 0; i < timepoints.length; i++ )
{
if ( timepoints[ i ] == timepoint )
return i;
}
return -1;
}
public static ArrayList<Integer> parseIntegerString(final String integers) throws ConfigurationParserException
{
if ( integers.trim().length() == 0 )
return new ArrayList<Integer>();
ArrayList<Integer> tmp = null;
try
{
tmp = new ArrayList<Integer>();
final String[] entries = integers.split(",");
for (String s: entries)
{
s = s.trim();
if (s.contains("-"))
{
int start = 0, end = 0, step;
start = Integer.parseInt(s.substring(0, s.indexOf("-")));
if (s.indexOf(":") < 0)
{
end = Integer.parseInt(s.substring(s.indexOf("-") + 1, s.length()));
step = 1;
}
else
{
end = Integer.parseInt(s.substring(s.indexOf("-") + 1, s.indexOf(":")));
step = Integer.parseInt(s.substring(s.indexOf(":") + 1, s.length()));
}
if (end > start)
for (int i = start; i <= end; i += step)
tmp.add(i);
else
for (int i = start; i >= end; i -= step)
tmp.add(i);
}
else
{
tmp.add(Integer.parseInt(s));
}
}
}
catch (final Exception e)
{
throw new ConfigurationParserException("Cannot parse pattern '" + integers + "'");
}
return tmp;
}
public void parseAngles() throws ConfigurationParserException
{
final ArrayList<Integer> tmp = parseIntegerString(anglePattern);
angles = new int[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
angles[i] = tmp.get(i);
// if there are no angles given take all
if ( angles.length == 0 )
{
final String replaceTL = getReplaceStringTimePoints( inputFilePattern );
final int numDigitsTL = replaceTL.length() - 2;
final String replaceAngle = getReplaceStringAngle( inputFilePattern );
String filePattern = inputFilePattern;
filePattern = filePattern.replace( replaceTL, getLeadingZeros( numDigitsTL, timepoints[ 0 ] ) );
filePattern = filePattern.replace( replaceAngle, "*" );
final String filePatternStart = filePattern.substring( 0, filePattern.indexOf( '*' ));
final String filePatternEnd = filePattern.substring( filePattern.indexOf( '*' ) + 1, filePattern.length() );
final String[] listing = getDirListing( inputdirectory, filePatternStart, filePatternEnd );
angles = new int[ listing.length ];
for ( int i = 0; i < listing.length; ++i )
{
String entry = listing[ i ];
entry = entry.substring( filePatternStart.length(), entry.length() - filePatternEnd.length() );
angles[ i ] = Integer.parseInt( entry );
}
}
}
public void parseChannels() throws ConfigurationParserException
{
if ( channelPattern != null && channelPattern.trim().length() > 0 )
{
final ArrayList<Integer> tmp = parseIntegerString( channelPattern );
channels = new int[ tmp.size() ];
for (int i = 0; i < tmp.size(); i++)
channels[i] = tmp.get(i);
}
else
{
// there is always channel 0
channels = new int[ 1 ];
// ...except when it is Huisken format, then we just take the first channel (which might not be 0)
if ( isHuiskenFormat() )
{
channels[0] = spimExperiment.channelStart;
}
}
IOFunctions.println( "ChannelPattern: " + channelPattern );
IOFunctions.println( "Channels: " + Util.printCoordinates( channels ) );
if ( channelsToRegister != null && channelsToRegister.trim().length() > 0 )
{
final ArrayList<Integer> tmp = parseIntegerString( channelsToRegister );
channelsRegister = new int[ tmp.size() ];
for (int i = 0; i < tmp.size(); i++)
channelsRegister[i] = tmp.get(i);
}
else
{
// there is always channel 0
channelsRegister = new int[ 1 ];
// ...except when it is Huisken format, then we just take the first channel (which might not be 0)
if ( isHuiskenFormat() )
{
channelsRegister[0] = spimExperiment.channelStart;
}
}
IOFunctions.println( "ChannelsToRegister: " + channelsToRegister );
IOFunctions.println( "ChannelsRegister: " + Util.printCoordinates( channelsRegister ) );
if ( channelsToFuse != null && channelsToFuse.trim().length() > 0 )
{
final ArrayList<Integer> tmp = parseIntegerString( channelsToFuse );
channelsFuse = new int[ tmp.size() ];
for (int i = 0; i < tmp.size(); i++)
channelsFuse[i] = tmp.get(i);
}
else
{
// there is always channel 0 - wrong, only always the same channel that also gets registered
// there is always the first channel
channelsFuse = new int[]{ channelsRegister[ 0 ] };
// ...except when it is Huisken format, then we just take the first channel (which might not be 0)
if ( isHuiskenFormat() )
{
channelsFuse[0] = spimExperiment.channelStart;
}
}
IOFunctions.println( "ChannelsToFuse: " + channelsToFuse );
IOFunctions.println( "ChannelsFuse: " + Util.printCoordinates( channelsFuse ) );
// test validity (channels for registration and fusion have to be a subclass of the channel pattern)
for ( final int cR : channelsRegister )
{
boolean contains = false;
for ( final int c : channels )
if ( c == cR )
contains = true;
if ( !contains )
{
throw new ConfigurationParserException( "Channel " + cR + " that should be used for registration is not part of the channels " +
Util.printCoordinates( channels ) );
}
}
for ( final int cF : channelsFuse )
{
boolean contains = false;
for ( final int c : channels )
if ( c == cF )
contains = true;
if ( !contains )
{
throw new ConfigurationParserException( "Channel " + cF + " that should be used for fusion is not part of the channels " +
Util.printCoordinates( channels ) );
}
}
// all channels in channels should be used for something
for ( final int c : channels )
{
boolean contains = false;
for ( final int cR : channelsRegister )
if ( c == cR )
contains = true;
for ( final int cF : channelsFuse )
if ( c == cF )
contains = true;
if ( !contains )
{
throw new ConfigurationParserException( "Channel " + c + " is not used for anything (not registration, not fusion); stopping. " );
}
}
if ( segmentation == SegmentationTypes.DOG && !fuseOnly )
{
final int numChannelsRegister = channelsRegister.length;
if ( numChannelsRegister != initialSigma.length || numChannelsRegister != minPeakValue.length )
throw new ConfigurationParserException( "The number of channels with beads does not match the number of DoG parameters." );
// auto-adjust minInitialPeakValue
if ( minInitialPeakValue == null || minInitialPeakValue.length != numChannelsRegister )
{
minInitialPeakValue = new float[ numChannelsRegister ];
for ( int i = 0; i < numChannelsRegister; ++i )
minInitialPeakValue[ i ] = minPeakValue[ i ] / 10;
}
}
// do we want to mirror some channels in advance??
if ( mirrorChannels.trim().length() > 0 )
{
final String[] mirror = mirrorChannels.trim().split( "," );
channelsMirror = new int[ mirror.length ][ 2 ];
int i = 0;
for ( String entry : mirror )
{
entry = entry.trim();
try
{
final int channel = Integer.parseInt( entry.substring( 0, entry.length() - 1 ) );
final String direction = entry.substring( entry.length()-1, entry.length() ).toLowerCase();
if ( direction.equalsIgnoreCase( "h" ) )
{
channelsMirror[ i ][ 0 ] = channel;
channelsMirror[ i ][ 1 ] = 0;
}
else if ( direction.equalsIgnoreCase( "v" ) )
{
channelsMirror[ i ][ 0 ] = channel;
channelsMirror[ i ][ 1 ] = 1;
}
else
{
throw new ConfigurationParserException( "Cannot parse channel mirroring information: " + entry + ": " + direction + " is unknown." );
}
i++;
}
catch ( final Exception e )
{
throw new ConfigurationParserException( "Cannot parse channel mirroring information: " + mirrorChannels.trim() + ": " + e );
}
}
}
}
public void parseIlluminations() throws ConfigurationParserException
{
if ( hasAlternatingIllumination() )
illuminations = new int[] {0, 1};
else
illuminations = new int[] {0};
}
protected String[] getDirListing( final String directory, final String filePatternStart, final String filePatternEnd )
{
final File dir = new File( directory );
// It is also possible to filter the list of returned files.
// This example does not return any files that start with `.'.
final FilenameFilter filter = new FilenameFilter()
{
@Override
public boolean accept(final File dir, final String name)
{
return name.startsWith( filePatternStart) && name.endsWith( filePatternEnd );
}
};
return dir.list(filter);
}
public void parseTimePoints() throws ConfigurationParserException
{
final ArrayList<Integer> tmp = parseIntegerString(timepointPattern);
timepoints = new int[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
timepoints[i] = tmp.get(i);
}
/*
public String getUniqueNameForTimePoint(int timePoint)
{
// find how to parse
String replaceTL = null, replaceAngle = null;
int numDigitsTL = 0;
int numDigitsAngle = 0;
int i1 = inputFilePattern.indexOf("{t");
int i2 = inputFilePattern.indexOf("t}");
if (i1 > 0 && i2 > 0)
{
replaceTL = "{";
numDigitsTL = i2 - i1;
for (int i = 0; i < numDigitsTL; i++)
replaceTL += "t";
replaceTL += "}";
}
i1 = inputFilePattern.indexOf("{a");
i2 = inputFilePattern.indexOf("a}");
if (i1 > 0 && i2 > 0)
{
replaceAngle = "{";
numDigitsAngle = i2 - i1;
for (int i = 0; i < numDigitsAngle; i++)
replaceAngle += "a";
replaceAngle += "}";
}
String fileName = inputFilePattern;
if (replaceTL != null)
fileName = fileName.replace(replaceTL, getLeadingZeros(numDigitsTL, timePoint));
fileName = fileName.replace(replaceAngle, "");
// cut the extension
fileName = fileName.substring(0, fileName.lastIndexOf("."));
// remove the angle string
fileName = fileName.replace(angleString, "");
return fileName;
}
*/
public static String getReplaceStringChannels( final String inputFilePattern )
{
String replacePattern = null;
int numDigitsTL = 0;
final int i1 = inputFilePattern.indexOf("{c");
final int i2 = inputFilePattern.indexOf("c}");
if (i1 >= 0 && i2 > 0)
{
replacePattern = "{";
numDigitsTL = i2 - i1;
for (int i = 0; i < numDigitsTL; i++)
replacePattern += "c";
replacePattern += "}";
}
return replacePattern;
}
public static String getReplaceStringTimePoints( final String inputFilePattern )
{
String replacePattern = null;
int numDigitsTL = 0;
final int i1 = inputFilePattern.indexOf("{t");
final int i2 = inputFilePattern.indexOf("t}");
if (i1 >= 0 && i2 > 0)
{
replacePattern = "{";
numDigitsTL = i2 - i1;
for (int i = 0; i < numDigitsTL; i++)
replacePattern += "t";
replacePattern += "}";
}
return replacePattern;
}
public static String getReplaceStringAngle( final String inputFilePattern )
{
String replacePattern = null;
int numDigitsTL = 0;
final int i1 = inputFilePattern.indexOf("{a");
final int i2 = inputFilePattern.indexOf("a}");
if (i1 >= 0 && i2 > 0)
{
replacePattern = "{";
numDigitsTL = i2 - i1;
for (int i = 0; i < numDigitsTL; i++)
replacePattern += "a";
replacePattern += "}";
}
return replacePattern;
}
public boolean isHuiskenFormat()
{
return spimExperiment != null;
}
public boolean hasAlternatingIllumination()
{
return isHuiskenFormat() && ( spimExperiment.d < ( spimExperiment.planeEnd + 1 - spimExperiment.planeStart ) );
}
public SPIMExperiment getSpimExperiment()
{
return spimExperiment;
}
public double getZStretchingHuisken()
{
return spimExperiment.pd / spimExperiment.pw;
}
public void getFilenamesHuisken() throws ConfigurationParserException
{
parseTimePoints();
parseAngles();
parseChannels();
parseIlluminations();
// generate some dummy filenames that will be used for bead/registration
// files
file = new File[ timepoints.length ][ channels.length ][ angles.length ][ illuminations.length ];
// int sample = spimExperiment.sampleStart;
// int region = spimExperiment.regionStart;
// int plane = spimExperiment.planeStart;
// int frame = spimExperiment.frameStart;
// final String pathFormatString =
// "s%03d/t%05d/r%03d/a%03d/c%03d/z%04d/%010d.dat";
final String pathFormatString = "reg-t%05d-a%03d-c%03d-i%01d";
for ( int tp = 0; tp < timepoints.length; ++tp )
for ( int channel = 0; channel < channels.length; ++channel )
for ( int angle = 0; angle < angles.length; ++angle )
for ( int illumination = 0; illumination < illuminations.length; ++illumination )
{
file[ tp ][ channel ][ angle ][ illumination ] = new File( inputdirectory, String.format( pathFormatString, timepoints[ tp ], angles[ angle ], channels[ channel ], illuminations[ illumination ] ) );
}
}
public void getFileNames() throws ConfigurationParserException
{
// find how to parse
String replaceTL = getReplaceStringTimePoints( inputFilePattern );
String replaceAngle = getReplaceStringAngle( inputFilePattern );
String replaceChannel = getReplaceStringChannels( inputFilePattern );
if ( replaceTL == null )
replaceTL = "\\";
if ( replaceAngle == null )
replaceAngle = "\\";
if ( replaceChannel == null )
replaceChannel = "\\";
final int numDigitsTL = Math.max( 0, replaceTL.length() - 2 );
final int numDigitsAngle = Math.max( 0, replaceAngle.length() - 2 );
final int numDigitsChannel = Math.max( 0, replaceChannel.length() - 2 );
parseTimePoints();
parseAngles();
parseChannels();
parseIlluminations();
if ( replaceAngle.equals( "\\" ) )
throw new ConfigurationParserException("You gave no pattern to substitute the angles in the file name");
if ( angles.length < 2 )
IOFunctions.println( "Warning: You gave less than two angles to process: " + anglePattern );
//throw new ConfigurationParserException("You gave less than two angles to process: " + anglePattern);
if (timepoints.length > 1 && replaceTL.equals( "\\" ) )
throw new ConfigurationParserException("You gave more than one timepoint but no pattern to replace");
file = new File[ timepoints.length ][ channels.length ][ angles.length ][ illuminations.length ];
for ( int tp = 0; tp < timepoints.length; ++tp )
for ( int channel = 0; channel < channels.length; ++channel )
for ( int angle = 0; angle < angles.length; ++angle )
for ( int illumination = 0; illumination < illuminations.length; ++illumination )
{
String fileName = inputFilePattern;
if ( replaceTL != null )
fileName = fileName.replace( replaceTL, getLeadingZeros( numDigitsTL, timepoints[ tp ] ) );
fileName = fileName.replace( replaceAngle, getLeadingZeros( numDigitsAngle, angles[ angle ] ) );
fileName = fileName.replace( replaceChannel, getLeadingZeros( numDigitsChannel, channels[ channel ] ) );
file[ tp ][ channel ][ angle ][ illumination ] = new File( inputdirectory, fileName );
}
}
public int getTimePointIndex( final int timepoint )
{
for ( int i = 0; i < timepoints.length; ++i )
if ( timepoints[ i ] == timepoint )
return i;
return -1;
}
private static String getLeadingZeros(final int zeros, final int number)
{
String output = "" + number;
while (output.length() < zeros)
output = "0" + output;
return output;
}
public void printProperties()
{
IOFunctions.println("timepointPattern: " + timepointPattern);
if (timepoints != null)
{
System.out.print("Time Points: ");
for (final int tp : timepoints)
System.out.print(tp + " ");
IOFunctions.println();
}
IOFunctions.println("anglePattern: " + anglePattern);
if (angles != null)
{
System.out.print("Angles: ");
for (final int angle : angles)
System.out.print(angle + " ");
IOFunctions.println();
}
//IOFunctions.println("angleString: " + angleString);
IOFunctions.println("inputFilePattern: " + inputFilePattern);
if (file != null)
for (int x = 0; x < file.length; x++)
for (int y = 0; y < file[x].length; y++)
IOFunctions.println("File["+x+"]["+y+"] = " + file[x][y]);
IOFunctions.println("inputdirectory: " + inputdirectory);
IOFunctions.println("outputdirectory: " + outputdirectory);
IOFunctions.println("registrationFiledirectory: " + registrationFiledirectory);
IOFunctions.println("debugLevel: " + debugLevel);
IOFunctions.println("showImageJWindow: " + showImageJWindow);
IOFunctions.println("timeLapseRegistration: " + timeLapseRegistration);
IOFunctions.println("referenceTimePoint: " + referenceTimePoint);
// image factories
inputImageFactory.printProperties();
processImageFactory.printProperties();
// for cached image arrays
IOFunctions.println("tempDir: " + tempDir);
// for the interpolation
//interpolatorFactorOutput.printProperties();
strategyFactoryOutput.printProperties();
// outofbounds strategy factories
strategyFactoryGauss.printProperties();
IOFunctions.println("writeOutputImage: " + writeOutputImage);
IOFunctions.println("showOutputImage: " + showOutputImage);
IOFunctions.println("segmentation type: " + segmentation);
IOFunctions.println("useEntropy: " + useEntropy);
IOFunctions.println("useGaussContentBased: " + useGaussContentBased);
IOFunctions.println("useIntegralContentBased: " + useIntegralContentBased);
IOFunctions.println("useLinearBlening: " + useLinearBlening);
IOFunctions.println("paralellFusion: " + paralellFusion);
IOFunctions.println("sequentialFusion: " + sequentialFusion);
IOFunctions.println("multipleImageFusion: " + multipleImageFusion);
IOFunctions.println("registerOnly: " + registerOnly);
IOFunctions.println("readSegmentation: " + readSegmentation);
IOFunctions.println("writeSegmentation: " + writeSegmentation);
IOFunctions.println("readRegistration: " + readRegistration);
IOFunctions.println("writeRegistration: " + writeRegistration);
IOFunctions.println("zStretching: " + zStretching);
IOFunctions.println("background: " + background);
// threshold segmentation
IOFunctions.println("threshold: " + threshold);
IOFunctions.println("fixed threshold: " + fixedThreshold);
IOFunctions.println("useFixedThreshold: " + useFixedThreshold);
IOFunctions.println("minBlackBorder: " + minBlackBorder);
IOFunctions.println("minSize: " + minSize);
IOFunctions.println("maxSize: " + maxSize);
IOFunctions.println("useCenterOfMass: " + useCenterOfMass);
// ScaleSpace Segmentation
IOFunctions.println("minPeakValue: " + minPeakValue);
IOFunctions.println("minInitialPeakValue: " + minInitialPeakValue);
IOFunctions.println("identityRadius: " + identityRadius);
IOFunctions.println("maximaTolerance: " + maximaTolerance);
IOFunctions.println("imageSigma: " + imageSigma);
IOFunctions.println("initialSigma: " + initialSigma);
IOFunctions.println("stepsPerOctave: " + stepsPerOctave);
IOFunctions.println("steps: " + steps);
// PointDescriptor properties
IOFunctions.println("differenceThreshold: " + differenceThreshold);
IOFunctions.println("ratioOfDistance: " + ratioOfDistance);
IOFunctions.println("neighbors: " + neighbors);
IOFunctions.println("useAssociatedBeads: " + useAssociatedBeads);
IOFunctions.println("useRANSAC: " + useRANSAC);
// RANSAC
IOFunctions.println("max_epsilon: " + max_epsilon);
IOFunctions.println("min_inlier_ratio: " + min_inlier_ratio);
IOFunctions.println("numIterations: " + numIterations);
// output image
IOFunctions.println("scale: " + scale);
IOFunctions.println("cropOffsetX: " + cropOffsetX);
IOFunctions.println("cropOffsetY: " + cropOffsetY);
IOFunctions.println("cropOffsetZ: " + cropOffsetZ);
IOFunctions.println("cropSizeX: " + cropSizeX);
IOFunctions.println("cropSizeY: " + cropSizeY);
IOFunctions.println("cropSizeZ: " + cropSizeZ);
IOFunctions.println("numberOfThreads: " + numberOfThreads);
// defines the sigma of the volumes injected
IOFunctions.println("sigma: " + sigma);
// where the injected Gaussian Distributions are cut off
IOFunctions.println("cutOffRadiusGauss: " + cutOffRadiusGauss);
// the number of histogram bins for computing the entropy
IOFunctions.println("histogramBins: " + histogramBins);
// the window Sizes for computing the local entropy
IOFunctions.println("windowSizeX: " + windowSizeX);
IOFunctions.println("windowSizeY: " + windowSizeY);
// linear blending
IOFunctions.println("alpha: " + alpha);
// gauss fusion
IOFunctions.println("fusionSigma1: " + fusionSigma1);
IOFunctions.println("fusionSigma2: " + fusionSigma2);
}
}