/*- * #%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.registration; import java.util.ArrayList; import mpicbg.imglib.image.Image; import mpicbg.imglib.io.LOCI; import mpicbg.imglib.type.numeric.real.FloatType; import mpicbg.models.AbstractAffineModel3D; import mpicbg.spim.fusion.FusionControl; import mpicbg.spim.io.IOFunctions; import mpicbg.spim.io.SPIMConfiguration; import mpicbg.spim.registration.bead.BeadRegistration; import mpicbg.spim.registration.bead.BeadSegmentation; import mpicbg.spim.registration.bead.error.GlobalErrorStatistics; import mpicbg.spim.registration.bead.error.GlobalErrorStatisticsImpl; /** * This class stores the links to all Views and initializes the View-dependent error statistics * * @author Stephan Preibisch * */ public class ViewStructure { final public static int DEBUG_ALL = 0; final public static int DEBUG_MAIN = 1; final public static int DEBUG_ERRORONLY = 2; public static int firstID = 0; /** * The link to the Views */ final protected ArrayList<ViewDataBeads> views; /** * The time point of the current view constellation */ final protected int timePoint; /** * The number of channels in this view constellation */ final protected int numChannels; /** * Arbitrary String for identification */ final protected String identification; /** * The debug level of this view constellation */ protected int debugLevel; /** * The configuration of the current SPIM registration */ final protected SPIMConfiguration conf; /** * The global error statistics of this view constellation */ protected GlobalErrorStatistics errorStatistics; /** * The object that handles segmentation */ protected BeadSegmentation beadSegment; /** * The object that handles registration */ protected BeadRegistration beadRegister; /** * The object that handles fusion */ protected FusionControl fusionControl; public ViewStructure( final ArrayList<ViewDataBeads> views, final SPIMConfiguration conf, final String id, final int timePoint, final int numChannels ) { this( views, conf, id, timePoint, numChannels, ViewStructure.DEBUG_MAIN ); } public ViewStructure( final ArrayList<ViewDataBeads> views, final SPIMConfiguration conf, final String id, final int timePoint, final int numChannels, final int debugLevel ) { this.views = views; this.identification = id; this.conf = conf; this.timePoint = timePoint; this.numChannels = numChannels; setDebugLevel( debugLevel ); this.errorStatistics = new GlobalErrorStatisticsImpl(); this.beadSegment = new BeadSegmentation( this ); for ( final ViewDataBeads view : views ) view.setViewStructure( this ); for ( final ViewDataBeads view : views ) view.initErrorStatistics(); beadSegment = new BeadSegmentation( this ); beadRegister = new BeadRegistration( this ); fusionControl = new FusionControl( ); } public BeadSegmentation getBeadSegmentation() { return beadSegment; } public BeadRegistration getBeadRegistration() { return beadRegister; } public FusionControl getFusionControl() { return fusionControl; } /** * The number of views in this view collection * @return the number of views */ public int getNumViews() { return getViews().size(); } /** * The number of channels in this view collection * @return the number of channels */ public int getNumChannels() { return numChannels; } /** * Returns the channel id for a certain channelIndex * @param channelIndex * @return the naming of the channel */ public int getChannelNum( final int channelIndex ) { for ( final ViewDataBeads view : getViews() ) if ( view.getChannelIndex() == channelIndex ) return view.getChannel(); return -1; } /** * The {@link GlobalErrorStatistics} collects error details of the registration prodedure * @return The {@link GlobalErrorStatistics} object of this {@link ViewStructure} */ public GlobalErrorStatistics getGlobalErrorStatistics() { return errorStatistics; } /** * Sets a new object that collects error details of the registration prodedure * @param errorStatistics - The {@link GlobalErrorStatistics} object of this {@link ViewStructure} */ public void setGlobalErrorStatistics( final GlobalErrorStatistics errorStatistics ) { this.errorStatistics = errorStatistics; } /** * DebugLevel of this view constellation * @return the current debug level */ public int getDebugLevel () { return debugLevel; } /** * DebugLevel of this view constellation * @param debugLevel - the new debug level of this view constellation */ public void setDebugLevel ( final int debugLevel ) { this.debugLevel = debugLevel; } /** * The time point index of the current {@link ViewStructure} * @return the id */ public int getTimePoint() { return timePoint; } /** * Return the current SPIMConfiguration * @return current {@link SPIMConfiguration} object */ public SPIMConfiguration getSPIMConfiguration() { return conf; } @Override public String toString() { return identification; } /** * get the identification String of the ViewStructure * @return String ID */ public String getID() { return identification; } /** * Get the views * * @return ArrayList containing all Views */ public ArrayList<ViewDataBeads> getViews() { return views; } /** * For getting a View with a certain ID * * @param viewID - the ID of the wanted View * @return the View with the respective id or null if it does not exist */ public ViewDataBeads getViewFromID( final int viewID ) { if ( viewID < views.size() ) if ( views.get( viewID ).getID() == viewID ) return views.get( viewID ); for ( final ViewDataBeads view : views ) if ( view.getID() == viewID ) return view; //IOFunctions.println( "ViewStructure.getView( " + viewID + " ): View not part of this ViewStructure" ); return null; } /** * Gets the number of dimensions from view 1 * @return - the numnber of dimensions */ public int getNumDimensions() { return views.get( 0 ).getImageSize().length; } /** * Loads the bead detections and its correspondences candidates as well as true correspondences from the *.beads.txt files in the registration file directory * * @return true if successful, false otherwise */ public boolean loadSegmentations() { for ( final ViewDataBeads view : getViews() ) { // only load those who are needed for registration if ( view.getUseForRegistration() ) { boolean readSeg = IOFunctions.readSegmentation( view, conf.registrationFiledirectory, conf ); if (!readSeg) { if ( debugLevel <= ViewStructure.DEBUG_ERRORONLY ) IOFunctions.printErr("Cannot read segmentation for " + view ); return false; } } } return true; } /** * Loads the registration matrix and the errors from the *.registration files in the registration file directory * * @return true if successful, false otherwise */ public boolean loadRegistrations() { boolean success = true; for ( final ViewDataBeads view : getViews() ) { boolean readReg = view.loadRegistration(); if (!readReg) { if ( getDebugLevel() <= ViewStructure.DEBUG_ERRORONLY ) IOFunctions.printErr( "Cannot read registration for view " + view + " in " + this ); success = false; } } return success; } /** * Loads the dimensions from the *.dim files in the registration file directory * * @return true if successful, false otherwise */ public boolean loadDimensions() { boolean success = true; for ( final ViewDataBeads view : getViews() ) { boolean readDim = view.loadDimensions(); if (!readDim) { if ( getDebugLevel() <= ViewStructure.DEBUG_ERRORONLY ) IOFunctions.printErr( "Cannot read dimensions for view " + view + " in " + this ); success = false; } } return success; } /** * This static methods creates an instance of {@link ViewStructure} with all {@link ViewDataBeads} completely instantiated. * Afterwards processing can start or already processed data can be loaded. * * @param conf - the {@link SPIMConfiguration} object containing all information about the current registration * @param timePointIndex - the id of the current time point as the {@link SPIMConfiguration} stores the information for all time points * @param model - the model to be used for registration * @param id - arbitrary id, will be printed with the toString method * @param debugLevel - the debug level of the program ViewStructure.DEBUG_ALL, ViewStructure.DEBUG_MAIN or ViewStructure.DEBUG_ERRORONLY * @return an instance of the ViewStructure, completely intialized */ public static <M extends AbstractAffineModel3D<M>> ViewStructure initViewStructure( final SPIMConfiguration conf, final int timePointIndex, final M model, final String id, final int debugLevel ) { final ArrayList<ViewDataBeads> views = new ArrayList<ViewDataBeads>(); double zStretching; if ( conf.overrideImageZStretching ) { zStretching = conf.zStretching; } else if ( conf.isHuiskenFormat() ) { IOFunctions.println( "Reading z-stretching from xml." ); zStretching = conf.getZStretchingHuisken(); IOFunctions.println( "z-stretching = " + zStretching ); } else { IOFunctions.println( "Opening first image to determine z-stretching." ); final Image<FloatType> image = LOCI.openLOCIFloatType( conf.file[ timePointIndex ][ 0 ][ 0 ][ 0 ].getPath(), conf.inputImageFactory ); if ( image == null ) { IOFunctions.println( "Cannot open fie: '" + conf.file[ timePointIndex ][ 0 ][ 0 ][ 0 ].getPath() + "'" ); return null; } zStretching = image.getCalibration( 2 ) / image.getCalibration( 0 ); IOFunctions.println( "z-stretching = " + zStretching ); image.close(); } int idNr = firstID; final int numChannels = conf.file[ timePointIndex ].length; IOFunctions.println( "Using model: " + model.getClass().getCanonicalName() ); for (int c = 0; c < conf.file[ timePointIndex ].length; c++) for (int a = 0; a < conf.file[ timePointIndex ][ c ].length; a++) for ( int i = 0; i < conf.file[ timePointIndex ][ c ][ a ].length; ++i ) { final ViewDataBeads view = new ViewDataBeads( idNr++, model.copy(), conf.file[ timePointIndex ][ c ][ a ][ i ].getPath(), zStretching ); int channelRegister = 0; view.setAcqusitionAngle( conf.angles[ a ] ); view.setChannel( conf.channels[ c ] ); view.setChannelIndex( c ); view.setTimePoint( conf.timepoints[timePointIndex] ); view.setIllumination( conf.illuminations[ i ] ); if ( numChannels == 1 ) { view.setUseForFusion( true ); view.setUseForRegistration( true ); view.setInitialSigma( conf.initialSigma[ channelRegister ] ); view.setMinPeakValue( conf.minPeakValue[ channelRegister ] ); view.setIntegralRadius1( conf.integralImgRadius1[ channelRegister ] ); view.setIntegralRadius2( conf.integralImgRadius2[ channelRegister ] ); view.setIntegralThreshold( conf.integralImgThreshold[ channelRegister ] ); } else { boolean contains = false; for ( final int cR : conf.channelsRegister ) if ( cR == view.getChannel() ) contains = true; view.setUseForRegistration( contains ); if ( contains ) { view.setInitialSigma( conf.initialSigma[ channelRegister ] ); view.setMinPeakValue( conf.minPeakValue[ channelRegister ] ); view.setIntegralRadius1( conf.integralImgRadius1[ channelRegister ] ); view.setIntegralRadius2( conf.integralImgRadius2[ channelRegister ] ); view.setIntegralThreshold( conf.integralImgThreshold[ channelRegister ] ); channelRegister++; } contains = false; for ( final int cF : conf.channelsFuse ) if ( cF == view.getChannel() ) contains = true; view.setUseForFusion( contains ); } if ( conf.channelsMirror != null ) { for ( final int[] mirror : conf.channelsMirror ) { if ( conf.channels[ c ] == mirror[ 0 ] ) { if ( mirror[ 1 ] == 0 ) view.setMirrorHorizontally( true ); if ( mirror[ 1 ] == 1 ) view.setMirrorVertically( true ); } } } views.add( view ); } final ViewStructure viewStructure = new ViewStructure( views, conf, id, conf.timepoints[ timePointIndex ], numChannels, debugLevel ); return viewStructure; } }