/*- * #%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.bead; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; import spim.vecmath.Transform3D; import spim.vecmath.Matrix4f; import spim.vecmath.Quat4f; import spim.vecmath.Vector3d; import spim.vecmath.Vector3f; import mpicbg.imglib.multithreading.SimpleMultiThreading; import mpicbg.models.AbstractAffineModel3D; import mpicbg.models.AffineModel3D; import mpicbg.models.IllDefinedDataPointsException; import mpicbg.models.Model; import mpicbg.models.NotEnoughDataPointsException; import mpicbg.models.RigidModel3D; import mpicbg.models.SimilarityModel3D; import mpicbg.models.TranslationModel3D; import mpicbg.spim.io.IOFunctions; import mpicbg.spim.io.SPIMConfiguration; import mpicbg.spim.mpicbg.PointMatchGeneric; import mpicbg.spim.mpicbg.TileConfigurationSPIM; import mpicbg.spim.registration.ViewDataBeads; import mpicbg.spim.registration.ViewStructure; import mpicbg.spim.registration.bead.error.GlobalErrorStatistics; import mpicbg.spim.registration.detection.DetectionRegistration; import mpicbg.spim.registration.detection.descriptor.CoordSystem3d; import mpicbg.spim.registration.detection.descriptor.CorrespondenceExtraction; import mpicbg.util.TransformUtils; public class BeadRegistration { public static float minInlierFactor = 3; public static boolean preAlignTiles = false; final ViewStructure viewStructure; final static NumberFormat nf = NumberFormat.getPercentInstance(); /** * Instantiates the object with a certain {@link ViewStructure} it is working on when using non-static method calls * @param viewStructure - the {@link ViewStructure} to work on */ public BeadRegistration( final ViewStructure viewStructure ) { this.viewStructure = viewStructure; } /** * The {@link ViewStructure} this {@link BeadRegistration} is working with * @return - the associated {@link ViewStructure} */ public ViewStructure getViewStructure() { return viewStructure; } /** * Registers the current {@link ViewStructure}, see {@link BeadRegistration#registerViews(ViewStructure)} */ public TileConfigurationSPIM registerViews() { return registerViews( viewStructure ); } /** * Registers the current {@link ViewStructure}, see {@link BeadRegistration#registerViews(ViewStructure)} */ public TileConfigurationSPIM registerViews( final boolean resetW ) { return registerViews( viewStructure, resetW ); } /** * Registers the template {@link ViewStructure} to the {@link ViewStructure} of this {@link BeadRegistration} object, see {@link BeadRegistration#registerViewStructure(ViewStructure, ViewStructure)} */ public void registerViewStructure( final ViewStructure template ) { registerViewStructure( viewStructure, template ); } /** * Registers the {@link ViewDataBeads} of the template {@link ViewStructure} to the {@link ViewDataBeads} of the reference {@link ViewStructure}. * All tiles of the reference {@link ViewStructure} are therefore fixed during the registration. * The {@link SPIMConfiguration} and {@link GlobalErrorStatistics} are taken from the template {@link ViewStructure}, * the debuglevel is the highest of template and reference. * * @param reference - the reference {@link ViewStructure} * @param template - the template {@link ViewStructure} */ public static void registerViewStructure( final ViewStructure reference, final ViewStructure template ) { final int debugLevel = Math.min( reference.getDebugLevel(), template.getDebugLevel() ); final GlobalErrorStatistics errorStatistics = template.getGlobalErrorStatistics(); final SPIMConfiguration conf = template.getSPIMConfiguration(); // we do not need to register if the reference time point is the same as the template time point if ( reference.getTimePoint() == template.getTimePoint() ) { for ( int view = 0; view < reference.getNumViews(); ++view ) { final ViewDataBeads templateView = template.getViews().get( view ); final ViewDataBeads referenceView = reference.getViews().get( view ); templateView.getTile().getModel().set( referenceView.getTile().getModel() ); for ( int i = 0; i < reference.getNumViews(); ++i ) if ( i != view ) templateView.getViewErrorStatistics().setViewConnected( template.getViews().get( i ), true ); } if ( conf.writeRegistration ) for ( ViewDataBeads view : template.getViews() ) view.writeRegistrationTimeLapse( template.getTimePoint() ); return; } // reset the models of the template (only if template does not equal reference) //AffineModel3D m = new AffineModel3D(); for ( final ViewDataBeads views : template.getViews() ) views.getTile().getModel().set( views.getUninitializedModel() ); // // compute the proper alignment // // Apply stretching and clear correspondences for ( final ViewDataBeads view : reference.getViews() ) { if ( debugLevel <= ViewStructure.DEBUG_ALL ) IOFunctions.println( view + ": " + (float)view.getZStretching() ); for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] *= (float)view.getZStretching(); bead.getDescriptorCorrespondence().clear(); bead.getRANSACCorrespondence().clear(); } } // Apply stretching and clear correspondences for ( final ViewDataBeads view : template.getViews() ) { if ( debugLevel <= ViewStructure.DEBUG_ALL ) IOFunctions.println( view + ": " + (float)view.getZStretching() ); for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] *= (float)view.getZStretching(); bead.getDescriptorCorrespondence().clear(); bead.getRANSACCorrespondence().clear(); } } // // Now we extract correspondences // final Vector <ViewDataBeads[]> comparePairs = new Vector<ViewDataBeads[]>(); // for now all template views with each other for ( int viewIndexA = 0; viewIndexA < template.getNumViews() - 1; viewIndexA++ ) for ( int viewIndexB = viewIndexA + 1; viewIndexB < template.getNumViews(); viewIndexB++ ) if ( template.getViews().get( viewIndexA ).getUseForRegistration() && template.getViews().get( viewIndexB ).getUseForRegistration() ) comparePairs.add( new ViewDataBeads[]{ template.getViews().get( viewIndexA ), template.getViews().get( viewIndexB )} ); // and all reference against all template views for ( int viewIndexA = 0; viewIndexA < reference.getNumViews(); viewIndexA++ ) for ( int viewIndexB = 0; viewIndexB < template.getNumViews(); viewIndexB++ ) if ( reference.getViews().get( viewIndexA ).getUseForRegistration() && reference.getViews().get( viewIndexB ).getUseForRegistration() ) comparePairs.add( new ViewDataBeads[]{ reference.getViews().get( viewIndexA ), template.getViews().get( viewIndexB )} ); final AtomicInteger ai = new AtomicInteger(0); Thread[] threads = SimpleMultiThreading.newThreads(); final int numThreads = threads.length; for ( int ithread = 0; ithread < threads.length; ++ithread ) threads[ithread] = new Thread(new Runnable() { public void run() { final int myNumber = ai.getAndIncrement(); final CorrespondenceExtraction<Bead> ce = new CoordSystem3d<Bead>(); //final CorrespondenceExtraction<Bead> ce = new Quaternion3d<Bead>(); //final CorrespondenceExtraction<Bead> ce = new CoordSystemSecure3d<Bead>( 800 ); for ( int i = 0; i < comparePairs.size(); i++ ) if ( i%numThreads == myNumber ) { final ViewDataBeads[] pair = comparePairs.get( i ); final ViewDataBeads viewA = pair[ 0 ]; final ViewDataBeads viewB = pair[ 1 ]; // extract candidates if ( debugLevel <= ViewStructure.DEBUG_ALL ) IOFunctions.println( viewA.getName() + "<->" + viewB.getName() + ": Starting Correspondence Extraction, " + viewA.getBeadStructure().getBeadList().size() + " <-> " + viewB.getBeadStructure().getBeadList().size() + " detection comparisons."); final ArrayList< PointMatchGeneric<Bead> > candidates = ce.extractCorrespondenceCandidates( viewA.getBeadStructure().getBeadList(), viewB.getBeadStructure().getBeadList(), conf.differenceThreshold, conf.ratioOfDistance, conf.useAssociatedBeads ); // compute ransac and remove inconsistent candidates final ArrayList< PointMatchGeneric<Bead> > correspondences = new ArrayList<PointMatchGeneric<Bead>>(); final Model<?> model = viewA.getTile().getModel().copy(); String result = DetectionRegistration.<BeadIdentification,Bead>computeRANSAC( candidates, correspondences, model, conf.max_epsilon, conf.min_inlier_ratio, minInlierFactor, conf.numIterations ); if ( debugLevel <= ViewStructure.DEBUG_MAIN ) IOFunctions.println( viewA.getName() + "<->" + viewB.getName() + ": " + result ); // update the error statistics synchronized ( errorStatistics ) { errorStatistics.setNumCandidates( errorStatistics.getNumCandidates() + candidates.size() ); } if ( correspondences.size() == 0 ) { viewA.getViewErrorStatistics().resetViewSpecificError( viewB ); } else { synchronized ( errorStatistics ) { errorStatistics.setNumCorrespondences( errorStatistics.getNumCorrespondences() + correspondences.size() ); errorStatistics.setAbsoluteLocalAlignmentError( errorStatistics.getAbsoluteLocalAlignmentError() + model.getCost() ); errorStatistics.setAlignmentErrorCount( errorStatistics.getAlignmentErrorCount() + 1 ); } // this does not has to be synchronized as there is always one pair only which is unique if ( viewA.getViewStructure() == viewB.getViewStructure() ) { viewA.getViewErrorStatistics().setViewSpecificError( viewB, model.getCost() ); viewB.getViewErrorStatistics().setViewSpecificError( viewA, model.getCost() ); } } // add them to the tiles DetectionRegistration.addPointMatches( correspondences, viewA.getTile(), viewB.getTile() ); } } }); SimpleMultiThreading.startAndJoin(threads); if ( debugLevel <= ViewStructure.DEBUG_MAIN ) { for ( ViewDataBeads view : reference.getViews() ) IOFunctions.println( view + " has " + view.getViewErrorStatistics().getNumTrueCorrespondencePairs() + " correspondences in " + view.getViewErrorStatistics().getNumConnectedViews() + " other views."); for ( ViewDataBeads view : template.getViews() ) IOFunctions.println( view + " has " + view.getViewErrorStatistics().getNumTrueCorrespondencePairs() + " correspondences in " + view.getViewErrorStatistics().getNumConnectedViews() + " other views."); IOFunctions.println( "The total number of detections was: " + errorStatistics.getNumDetections() ); IOFunctions.println( "The total number of true correspondences is: " + errorStatistics.getNumCorrespondences() ); IOFunctions.println( "The total number of correspondence candidates was: " + errorStatistics.getNumCandidates() ); final float ratio = ((float)errorStatistics.getNumCorrespondences() / (float)errorStatistics.getNumCandidates()); IOFunctions.println( "The ratio is: " + nf.format( ratio ) ); } // // Now we optimize everything // final ArrayList<ViewDataBeads> views = new ArrayList<ViewDataBeads>(); views.addAll( reference.getViews() ); views.addAll( template.getViews() ); // optimize the tiles but fix all the reference tiles // get the number of tiles used for registration of the reference int numTilesReference = 0; for ( final ViewDataBeads view : reference.getViews() ) if ( view.getUseForRegistration() ) numTilesReference++; optimizeTiles( views, numTilesReference, errorStatistics, debugLevel ); // unapply stretching for ( final ViewDataBeads view : reference.getViews() ) { for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] /= (float)view.getZStretching(); bead.resetW(); } } for ( final ViewDataBeads view : template.getViews() ) { for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] /= (float)view.getZStretching(); bead.resetW(); } } // write the registration data if ( conf.writeRegistration ) for ( ViewDataBeads view : template.getViews() ) view.writeRegistrationTimeLapse( reference.getTimePoint() ); } public static TileConfigurationSPIM registerViews( final ViewStructure viewStructure ) { return registerViews( viewStructure, true ); } /** * Registers all {@link ViewDataBeads} within a given {@link ViewStructure}, taking the first view as fixed Tile * Registration works without z-scaling, it has to be concatenated afterwards if wanted * * @param viewStructure - The {@link ViewStructure} to register */ public static TileConfigurationSPIM registerViews( final ViewStructure viewStructure, final boolean resetW ) { final ArrayList<ViewDataBeads> views = viewStructure.getViews(); final GlobalErrorStatistics errorStatistics = viewStructure.getGlobalErrorStatistics(); final SPIMConfiguration conf = viewStructure.getSPIMConfiguration(); // Apply stretching and clear correspondences for ( final ViewDataBeads view : views ) { if ( viewStructure.getDebugLevel() <= ViewStructure.DEBUG_ALL ) IOFunctions.println( view + ": " + (float)view.getZStretching() ); for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] *= (float)view.getZStretching(); bead.getDescriptorCorrespondence().clear(); bead.getRANSACCorrespondence().clear(); } } // // Now we extract correspondences // final Vector <int[]> comparePairs = new Vector<int[]>(); // count the number of detections ( possible candidates ) for ( final ViewDataBeads view : views ) errorStatistics.setNumDetections( errorStatistics.getNumDetections() + view.getViewErrorStatistics().getNumDetections() ); // determine which view pairs to compare for ( int viewIndexA = 0; viewIndexA < views.size() - 1; viewIndexA++ ) for ( int viewIndexB = viewIndexA + 1; viewIndexB < views.size(); viewIndexB++ ) if ( views.get( viewIndexA ).getUseForRegistration() && views.get( viewIndexB ).getUseForRegistration() ) comparePairs.add( new int[]{viewIndexA, viewIndexB} ); final AtomicInteger ai = new AtomicInteger(0); Thread[] threads = SimpleMultiThreading.newThreads(); final int numThreads = threads.length; for ( int ithread = 0; ithread < threads.length; ++ithread ) threads[ithread] = new Thread(new Runnable() { public void run() { final int myNumber = ai.getAndIncrement(); final CorrespondenceExtraction<Bead> ce = new CoordSystem3d<Bead>(); //final CorrespondenceExtraction<Bead> ce = new ModelBased3d<Bead>( new SubsetMatcher( 3, 4 ) ); //final CorrespondenceExtraction<Bead> ce = new CoordSystemSecure3d<Bead>( 2 ); for ( int i = 0; i < comparePairs.size(); i++ ) if ( i%numThreads == myNumber ) { final int[] pair = comparePairs.get( i ); final ViewDataBeads viewA = views.get( pair[0] ); final ViewDataBeads viewB = views.get( pair[1] ); // extract candidates if ( viewStructure.getDebugLevel() <= ViewStructure.DEBUG_ALL ) IOFunctions.println( viewA.getName() + "<->" + viewB.getName() + ": Starting Correspondence Extraction, " + viewA.getBeadStructure().getBeadList().size() + " <-> " + viewB.getBeadStructure().getBeadList().size() + " detection comparisons."); final ArrayList< PointMatchGeneric<Bead> > candidates = ce.extractCorrespondenceCandidates( viewA.getBeadStructure().getBeadList(), viewB.getBeadStructure().getBeadList(), conf.differenceThreshold, conf.ratioOfDistance, conf.useAssociatedBeads ); // compute ransac and remove inconsistent candidates final ArrayList< PointMatchGeneric<Bead> > correspondences = new ArrayList<PointMatchGeneric<Bead>>(); final Model<?> model = viewA.getTile().getModel().copy(); String result = DetectionRegistration.<BeadIdentification,Bead>computeRANSAC( candidates, correspondences, model, conf.max_epsilon, conf.min_inlier_ratio, minInlierFactor, conf.numIterations ); if ( viewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN ) IOFunctions.println( viewA.getName() + "<->" + viewB.getName() + ": " + result ); // update the error statistics synchronized ( errorStatistics ) { errorStatistics.setNumCandidates( errorStatistics.getNumCandidates() + candidates.size() ); } if ( correspondences.size() == 0 ) { viewA.getViewErrorStatistics().resetViewSpecificError( viewB ); } else { synchronized ( errorStatistics ) { errorStatistics.setNumCorrespondences( errorStatistics.getNumCorrespondences() + correspondences.size() ); errorStatistics.setAbsoluteLocalAlignmentError( errorStatistics.getAbsoluteLocalAlignmentError() + model.getCost() ); errorStatistics.setAlignmentErrorCount( errorStatistics.getAlignmentErrorCount() + 1 ); } // this does not has to be synchronized as there is always one pair only which is unique if ( viewA.getViewStructure() == viewB.getViewStructure() ) { viewA.getViewErrorStatistics().setViewSpecificError( viewB, model.getCost() ); viewB.getViewErrorStatistics().setViewSpecificError( viewA, model.getCost() ); } } // add them to the tiles DetectionRegistration.addPointMatches( correspondences, viewA.getTile(), viewB.getTile() ); } } }); SimpleMultiThreading.startAndJoin(threads); if ( viewStructure.getDebugLevel() <= ViewStructure.DEBUG_MAIN ) { for ( ViewDataBeads view : views ) IOFunctions.println( view + " has " + view.getViewErrorStatistics().getNumTrueCorrespondencePairs() + " correspondences in " + view.getViewErrorStatistics().getNumConnectedViews() + " other views."); IOFunctions.println( "The total number of detections was: " + errorStatistics.getNumDetections() ); IOFunctions.println( "The total number of correspondence candidates was: " + errorStatistics.getNumCandidates() ); IOFunctions.println( "The total number of true correspondences is: " + errorStatistics.getNumCorrespondences() ); } //Rigid-body //NucleiRegistration.optimizeTiles(rigidTileList); //System.exit( 0 ); // // Now we optimize everything // TileConfigurationSPIM tc = optimizeTiles( views, errorStatistics, viewStructure.getDebugLevel() ); // unapply stretching for ( ViewDataBeads view : views ) { for ( final Bead bead : view.getBeadStructure().getBeadList() ) { bead.getL()[2] /= (float)view.getZStretching(); if ( resetW ) bead.resetW(); } } if ( conf.writeRegistration ) { for ( ViewDataBeads view : views ) { // write bead data including correspondences view.writeSegmentation(); // write the registration data view.writeRegistration(); } } return tc; } public static void computeErrors( final ArrayList<ViewDataBeads> views, final TileConfigurationSPIM tc ) { tc.computeError(); } public static TileConfigurationSPIM optimizeTiles( final ArrayList<ViewDataBeads> views, final GlobalErrorStatistics errorStatistics, final int debugLevel ) { return optimizeTiles( views, 1, errorStatistics, debugLevel ); } public static TileConfigurationSPIM optimizeTiles( final ArrayList<ViewDataBeads> views, final int numFixed, final GlobalErrorStatistics errorStatistics, final int debugLevel ) { final TileConfigurationSPIM tc = new TileConfigurationSPIM( debugLevel ); int fixedTiles = 0; for ( final ViewDataBeads view : views ) { if (view.getTile().getConnectedTiles().size() > 0) { tc.addTile(view.getTile()); if ( fixedTiles < numFixed ) { if ( debugLevel <= ViewStructure.DEBUG_MAIN ) IOFunctions.println( "Fixing tile " + view ); tc.fixTile(view.getTile()); fixedTiles++; } } } try { if ( preAlignTiles ) { int unaligned = tc.preAlign().size(); if ( unaligned > 0 ) IOFunctions.println( "pre-aligned all tiles but " + unaligned ); else IOFunctions.println( "prealigned all tiles" ); } tc.optimize( 10, 10000, 200, debugLevel ); //tc.optimizeWithSketchTikZ( 10, 10000, 200, debugLevel ); //tc.optimizeWithSketchTikZNuclei( 10, 10000, 200, debugLevel ); /*tc.optimizeWithErrorAnalysis( 10, 10000, 200, conf, showDetails ); ArrayList<Double> distances = tc.getDistances(); ArrayList<Double> xd = tc.getXDistances(); ArrayList<Double> yd = tc.getYDistances(); ArrayList<Double> zd = tc.getZDistances(); PrintWriter out = fileAccess.openFileWrite( conf.inputdirectory + "distances.txt"); for ( Double distance : distances ) out.println( distance ); out.close(); out = fileAccess.openFileWrite( conf.inputdirectory + "xyzdistances.txt"); out.println( "x" + "\t" + "y" + "\t" + "z" ); for ( int i = 0; i < xd.size(); i++ ) out.println( xd.get(i) + "\t" + yd.get(i) + "\t" + zd.get(i) ); out.close(); */ /* for ( final ViewDataBeads view : views ) { final double maxDistanceCorrespondence = PointMatch.maxDistance( view.getTile().getMatches() ); final double avgDistanceCorrespondence = view.getTile().getDistance(); IOFunctions.println( view.getName() + " " + avgDistanceCorrespondence + " (" + maxDistanceCorrespondence + ")" ); } */ errorStatistics.setAverageAlignmentError( tc.getError() ); errorStatistics.setMinAlignmentError( tc.getMinError() ); errorStatistics.setMaxAlignmentError( tc.getMaxError() ); } catch ( NotEnoughDataPointsException e ) { e.printStackTrace(); errorStatistics.setAverageAlignmentError( Double.MAX_VALUE ); errorStatistics.setMinAlignmentError( Double.MAX_VALUE ); errorStatistics.setMaxAlignmentError( Double.MAX_VALUE ); } catch ( IllDefinedDataPointsException e ) { e.printStackTrace(); errorStatistics.setAverageAlignmentError( Double.MAX_VALUE ); errorStatistics.setMinAlignmentError( Double.MAX_VALUE ); errorStatistics.setMaxAlignmentError( Double.MAX_VALUE ); } if ( debugLevel <= ViewStructure.DEBUG_MAIN ) IOFunctions.println("Optimizer Matrices"); for ( final ViewDataBeads view : views ) { if ( view.getTile().getConnectedTiles().size() > 0 ) { if ( debugLevel <= ViewStructure.DEBUG_MAIN ) { IOFunctions.println( view + ":"); IOFunctions.println( "Transformation:\n"+ view.getTile().getModel() ); Transform3D t = TransformUtils.getTransform3D1( (AbstractAffineModel3D<?>)view.getTile().getModel() ); Vector3d s = new Vector3d(); t.getScale( s ); if ( view.getViewStructure().getDebugLevel() <= ViewStructure.DEBUG_MAIN ) IOFunctions.println( "Scaling: " + s ); // if it was a rigid model, output approx. rotation axis and rotation angle if ( view.getTile().getModel() instanceof RigidModel3D ) { final Matrix4f matrix = new Matrix4f(); TransformUtils.getTransform3D( ( (RigidModel3D)view.getTile().getModel() ) ).get( matrix ); final Quat4f qu = new Quat4f(); qu.set( matrix ); final Vector3f n = new Vector3f(qu.getX(),qu.getY(), qu.getZ()); n.normalize(); if ( view.getViewStructure().getDebugLevel() <= ViewStructure.DEBUG_MAIN ) { IOFunctions.println( "Approx. Axis: " + n ); IOFunctions.println( "Approx. Angle: " + Math.toDegrees( Math.acos( qu.getW() ) * 2 ) ); } } } } else { if ( view.getUseForRegistration() ) { for ( final ViewDataBeads otherView : views ) view.getViewErrorStatistics().resetViewSpecificError( otherView ); view.getBeadStructure().clearAllRANSACCorrespondences(); if ( debugLevel <= ViewStructure.DEBUG_MAIN ) IOFunctions.println( view + ": is not connected to any other tile!" ); } } } // now update the registration in all channels where no registration was performed to the one in channelIndex 0 for ( final ViewDataBeads view : views ) { if ( !view.getUseForRegistration() ) { final int angle = view.getAcqusitionAngle(); final int timepoint = view.getViewStructure().getTimePoint(); for ( final ViewDataBeads view2 : views ) { if ( view2.getAcqusitionAngle() == angle && timepoint == view2.getViewStructure().getTimePoint() && view2.getUseForRegistration() == true ) { view.getTile().getModel().set( view2.getTile().getModel() ); break; } } } } return tc; } public static void concatenateAxialScaling( final AbstractAffineModel3D model, final double zStretching ) { if ( model != null ) { if ( model instanceof AffineModel3D ) { final AffineModel3D tmpModel = new AffineModel3D(); final float z = (float)zStretching; tmpModel.set( 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, z, 0f ); ((AffineModel3D)model).concatenate( tmpModel ); } else if ( model instanceof RigidModel3D ) { final RigidModel3D tmpModel = new RigidModel3D(); final float z = (float)zStretching; tmpModel.set( 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, z, 0f ); ((RigidModel3D)model).concatenate( tmpModel ); } else if ( model instanceof TranslationModel3D ) { IOFunctions.println( "Cannot concatenate Axial Scaling with TranslationModel3D, you can load the registration as Affine or Rigid model and run it then!" ); } else { IOFunctions.println( "Cannot concatenate Axial Scaling, unknown model: " + model.getClass().getSimpleName() ); } } } public static void concatenateAxialScaling( final ViewDataBeads view, final int debugLevel ) { final AbstractAffineModel3D<?> m = (AbstractAffineModel3D<?>)view.getTile().getModel(); if ( m != null ) { concatenateAxialScaling( m, view.getZStretching() ); /* final AffineModel3D tmpModel = new AffineModel3D(); final float z = (float)view.getZStretching(); tmpModel.set( 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, z, 0f ); m.concatenate( tmpModel ); */ if ( debugLevel <= ViewStructure.DEBUG_ALL ) IOFunctions.println( view + "(" + view.getZStretching() + "): " + m ); } } public static void concatenateAxialScaling( final ArrayList<ViewDataBeads> views, final int debugLevel ) { if ( debugLevel <= ViewStructure.DEBUG_ALL ) IOFunctions.println("----------------------Scaling corrected-------------------"); // // update target registration // for ( final ViewDataBeads view : views) concatenateAxialScaling( view, debugLevel ); } }