/*-
* #%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;
import fiji.plugin.timelapsedisplay.RegistrationStatistics;
import java.util.ArrayList;
import java.util.Date;
import mpicbg.models.Point;
import mpicbg.spim.io.ConfigurationParserException;
import mpicbg.spim.io.ConfigurationParserGeneral;
import mpicbg.spim.io.ConfigurationParserSPIM;
import mpicbg.spim.io.IOFunctions;
import mpicbg.spim.io.ProgramConfiguration;
import mpicbg.spim.io.SPIMConfiguration;
import mpicbg.spim.registration.ViewDataBeads;
import mpicbg.spim.registration.ViewStructure;
import mpicbg.spim.registration.bead.Bead;
import mpicbg.spim.registration.bead.BeadIdentification;
import mpicbg.spim.registration.bead.BeadRegistration;
public class Reconstruction
{
final protected SPIMConfiguration conf;
public SPIMConfiguration getSPIMConfiguration() { return conf; }
ArrayList<RegistrationStatistics> stats;
public ArrayList<RegistrationStatistics> getRegistrationStatistics() { return stats; }
ViewStructure currentViewStructure = null;
public ViewStructure getCurrentViewStructure() { return currentViewStructure; }
public Reconstruction( final SPIMConfiguration conf )
{
IOFunctions.println( "Version 0.55" );
this.conf = conf;
if ( conf.collectRegistrationStatistics )
stats = new ArrayList<RegistrationStatistics>();
if ( conf.timeLapseRegistration )
processTimeLapse( conf );
else
processIndividualViewStructure( conf );
}
protected void findAllRansacCorrespondencesRecurively( final Bead bead, ArrayList<Bead> correspondingBeadList )
{
if ( bead.isUsed() )
return;
correspondingBeadList.add( bead );
bead.setUsed( true );
final ArrayList<BeadIdentification> ransacList = bead.getRANSACCorrespondence();
for ( final BeadIdentification correspondence : ransacList )
{
final Bead correspondingBead = correspondence.getBead();
if ( !correspondingBead.isUsed() )
findAllRansacCorrespondencesRecurively( correspondingBead, correspondingBeadList );
}
}
protected ArrayList<Bead> getAveragedBeadList( final ArrayList<ViewDataBeads> views, final ViewDataBeads newView )
{
final ArrayList<Bead> averagedBeadList = new ArrayList<Bead>();
BeadRegistration.concatenateAxialScaling( views, ViewStructure.DEBUG_ERRORONLY );
for( ViewDataBeads view : views )
{
//IOFunctions.println( "Analyzing view " + view.shortName );
final ArrayList<Bead> beadList = view.getBeadStructure().getBeadList();
for ( final Bead bead : beadList )
{
final ArrayList<Bead> correspondingBeadList = new ArrayList<Bead>();
findAllRansacCorrespondencesRecurively( bead, correspondingBeadList );
// if we find more than one bead we average their positions
if ( correspondingBeadList.size() > 1 )
{
Point location = new Point( new double[]{0,0,0} );
for ( final Bead correspondingBead : correspondingBeadList )
{
correspondingBead.apply( correspondingBead.getView().getTile().getModel() );
location.getW()[ 0 ] += correspondingBead.getW()[ 0 ];
location.getW()[ 1 ] += correspondingBead.getW()[ 1 ];
location.getW()[ 2 ] += correspondingBead.getW()[ 2 ];
//IOFunctions.println( correspondingBead );
}
location.getW()[ 0 ] /= correspondingBeadList.size();
location.getW()[ 1 ] /= correspondingBeadList.size();
location.getW()[ 2 ] /= correspondingBeadList.size();
averagedBeadList.add( new Bead( averagedBeadList.size(), location.getW().clone(), newView ) );
//IOFunctions.println( location );
//IOFunctions.println();
}
}
}
// clean up
for( ViewDataBeads view : views )
for ( final Bead bead : view.getBeadStructure().getBeadList() )
bead.setUsed( false );
return averagedBeadList;
}
protected void processTimeLapse( SPIMConfiguration conf )
{
for (int timePointIndex = 0; timePointIndex < conf.file.length; timePointIndex++)
{
final ViewStructure reference = ViewStructure.initViewStructure( conf, conf.getTimePointIndex( conf.referenceTimePoint ), conf.getModel(), "Reference ViewStructure Timepoint " + conf.referenceTimePoint, conf.debugLevelInt );
currentViewStructure = ViewStructure.initViewStructure( conf, timePointIndex, conf.getModel(), "Template ViewStructure Timepoint " + conf.timepoints[timePointIndex], conf.debugLevelInt );
//
// get timepoint information
//
if ( reference.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Loading reference timepoint information " + reference);
reference.loadDimensions();
reference.loadSegmentations();
reference.loadRegistrations();
if ( reference.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Loading timepoint " + currentViewStructure + " information");
currentViewStructure.loadDimensions();
currentViewStructure.loadSegmentations();
// update the ids of the template timepoint so that there are no identical ids
int id = reference.getViews().get( 0 ).getID();
for ( ViewDataBeads view : reference.getViews() )
if ( view.getID() >= id )
id = view.getID() + 1;
for ( ViewDataBeads view : currentViewStructure.getViews() )
{
view.setID( id++ );
if ( reference.getDebugLevel() <= ViewStructure.DEBUG_ALL )
IOFunctions.println( view + ", updated id" );
}
boolean readReg = conf.readRegistration;
if ( readReg )
for ( ViewDataBeads view : currentViewStructure.getViews() )
{
readReg &= view.loadRegistrationTimePoint( reference.getTimePoint() );
if ( !readReg )
break;
}
if ( !readReg )
reference.getBeadRegistration().registerViewStructure( currentViewStructure );
BeadRegistration.concatenateAxialScaling( reference.getViews(), reference.getDebugLevel() );
BeadRegistration.concatenateAxialScaling( currentViewStructure.getViews(), currentViewStructure.getDebugLevel() );
//
// remove the beads
//
// for ( final ViewDataBeads view : template.getViews() )
// RemoveBeads.removeBeads( view );
//
// add an external transformation
//
addExternalTransformation( currentViewStructure );
addExternalTransformation( reference );
//System.out.println( "conf.referenceTimePoint: " + conf.referenceTimePoint );
//System.out.println( "conf.getTimePointIndex( conf.referenceTimePoint ): " + conf.getTimePointIndex( conf.referenceTimePoint ) );
//System.out.println( "timePointIndex: " + timePointIndex );
//System.out.println( "conf.fuseReferenceTimepoint: " + conf.fuseReferenceTimepoint );
// if the reference timepoint was just added to compute the correct bounding box do not fuse it
if ( conf.getTimePointIndex( conf.referenceTimePoint ) == timePointIndex && !conf.fuseReferenceTimepoint )
{
//System.out.println( "yes." );
continue;
}
if ( !conf.registerOnly )
{
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Starting Fusion for timepoint " + conf.timepoints[timePointIndex]);
currentViewStructure.getFusionControl().fuse( currentViewStructure, reference, currentViewStructure.getTimePoint() );
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Finished Fusion for timepoint " + conf.timepoints[timePointIndex]);
}
//
// close all images, except if called as deconvolution as we still need the data
//
if ( !conf.isDeconvolution )
{
for ( ViewDataBeads view : currentViewStructure.getViews() )
view.closeImage();
}
else
{
conf.instance.deconvolve( currentViewStructure, conf, currentViewStructure.getTimePoint() );
}
}
}
protected void processIndividualViewStructure( SPIMConfiguration conf )
{
for ( int timePointIndex = 0; timePointIndex < conf.file.length; timePointIndex++ )
{
currentViewStructure = ViewStructure.initViewStructure( conf, timePointIndex, conf.getModel(), "ViewStructure Timepoint " + timePointIndex, conf.debugLevelInt );
// no file found
if ( currentViewStructure == null )
continue;
//
// Segmentation
//
if ( currentViewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Starting Bead Extraction");
boolean dimSuccess = false, segSuccess = false;
if ( currentViewStructure.getSPIMConfiguration().readSegmentation )
{
dimSuccess = currentViewStructure.loadDimensions();
if ( !dimSuccess )
{
if ( currentViewStructure.getDebugLevel() <= ViewStructure.DEBUG_ERRORONLY )
IOFunctions.println( "Cannot find files for " + currentViewStructure );
return;
}
segSuccess = currentViewStructure.loadSegmentations();
}
if ( !segSuccess )
currentViewStructure.getBeadSegmentation().segment();
/*
Image<FloatType> img = viewStructure.getBeadSegmentation().getFoundBeads( viewStructure.getViews().get( 0) );
img.getDisplay().setMinMax();
ImageJFunctions.copyToImagePlus(img).show();
*/
if ( currentViewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Finished Bead Extraction");
//
// Registration
//
if ( currentViewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Starting Registration");
boolean regSuccess = false;
if ( currentViewStructure.getSPIMConfiguration().readRegistration )
regSuccess = currentViewStructure.loadRegistrations();
if ( !regSuccess )
currentViewStructure.getBeadRegistration().registerViews();
// relocalize true correspondences?
if ( conf.doFit == 2 )
{
do
{
currentViewStructure.getBeadSegmentation().reLocalizeTrueCorrespondences( true );
// reset the error statistics and correspondences
currentViewStructure.getGlobalErrorStatistics().reset();
for ( final ViewDataBeads view : currentViewStructure.getViews() )
{
view.initErrorStatistics();
view.getBeadStructure().clearAllRANSACCorrespondences();
}
currentViewStructure.getBeadRegistration().registerViews();
}
while ( currentViewStructure.getBeadSegmentation().reLocalizeTrueCorrespondences( false ) > 0 );
for ( final ViewDataBeads view : currentViewStructure.getViews() )
view.closeImage();
}
BeadRegistration.concatenateAxialScaling( currentViewStructure.getViews(), currentViewStructure.getDebugLevel() );
if ( currentViewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Finished Registration");
//
// remove the beads
//
//for ( final ViewDataBeads view : viewStructure.getViews() )
//RemoveBeads.removeBeads( view );
//
// Predisplay result
//
//if ( conf.showOutputImage )
//new PreviewRegistration( viewStructure );
//
// add an external transformation
//
addExternalTransformation( currentViewStructure );
//
// Fusion
//
if (!conf.registerOnly)
{
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Starting Fusion");
currentViewStructure.getFusionControl().fuse( currentViewStructure, conf.timepoints[timePointIndex] );
if ( !conf.isDeconvolution )
IOFunctions.println("(" + new Date(System.currentTimeMillis()) + "): Finished Fusion");
}
//
// close all images, except if called as deconvolution as we still need the data
//
if ( !conf.isDeconvolution )
{
for ( ViewDataBeads view : currentViewStructure.getViews() )
view.closeImage();
}
else
{
conf.instance.deconvolve( currentViewStructure, conf, conf.timepoints[timePointIndex] );
}
// collect some information if wanted
if ( conf.collectRegistrationStatistics )
stats.add( new RegistrationStatistics( currentViewStructure ) );
if ( !conf.isDeconvolution )
IOFunctions.println( "Finished processing." );
}
}
protected void addExternalTransformation( final ViewStructure viewStructure )
{
//final AffineModel3D model = new AffineModel3D();
// 5 angle
//model.set( 0.87249345f, -0.48363087f, -0.06975689f, 0.0f, 0.48480982f, 0.87462026f, 0.0f, 0.0f, 0.06101087f, -0.033818856f, 0.9975669f, 0.0f );
// 6 angle red beads
//model.set( 0.78610414f, 0.38340846f, 0.4848098f, 0.0f, -0.43837133f, 0.89879465f, 0.0f, 0.0f, -0.43574473f, -0.2125268f, 0.87462026f, 0.0f );
// 6 angle Jans SPIM
/*
model.set(-0.39859658f, -0.88088614f, 0.25526524f, 0f,
0.909124f, -0.41619343f, -0.01663096f, 0f,
0.120889686f, 0.2254387f, 0.96672803f, 0);
*/
//for ( final ViewDataBeads view : viewStructure.getViews() )
//{
// final AffineModel3D viewModel = (AffineModel3D)view.getTile().getModel();
// viewModel.preConcatenate( model );
//}
}
public static void main( String[] args )
{
SPIMConfiguration config = null;
try
{
String temp;
if ( args == null || args.length == 0 || args[0].trim().length() < 1 )
temp = "spimconfig/configuration.txt";
else
temp = args[0].trim();
config = ConfigurationParserSPIM.parseFile( temp );
if ( config.debugLevelInt <= ViewStructure.DEBUG_ALL )
config.printProperties();
}
catch ( ConfigurationParserException e )
{
IOFunctions.println( "Cannot open SPIM configuration file: \n" + e );
e.printStackTrace();
return;
}
if ( config.showImageJWindow )
{
// read&parse configuration file
ProgramConfiguration conf = null;
try
{
conf = ConfigurationParserGeneral.parseFile( "config/configuration.txt" );
}
catch (final Exception e)
{
IOFunctions.println( "Cannot open configuration file: \n" + e );
}
// open imageJ window
if ( conf != null )
{
System.getProperties().setProperty( "plugins.dir", conf.pluginsDir );
final String params[] = { "-ijpath " + conf.pluginsDir };
// call the imageJ main class
ij.ImageJ.main( params );
}
else
{
final String params[] = { "-ijpath ." };
// call the imageJ main class
ij.ImageJ.main( params );
}
}
new Reconstruction( config );
}
}