/*- * #%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 spim.fiji.plugin; import ij.ImageJ; import ij.gui.GenericDialog; import ij.plugin.PlugIn; import java.awt.TextField; import java.util.ArrayList; import java.util.Collection; import java.util.List; import mpicbg.spim.data.SpimData; import mpicbg.spim.data.generic.AbstractSpimData; import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; import mpicbg.spim.data.generic.sequence.BasicViewDescription; import mpicbg.spim.data.generic.sequence.BasicViewSetup; import mpicbg.spim.data.sequence.FinalVoxelDimensions; import mpicbg.spim.data.sequence.TimePoint; import mpicbg.spim.data.sequence.ViewDescription; import mpicbg.spim.data.sequence.ViewId; import mpicbg.spim.data.sequence.ViewSetup; import mpicbg.spim.data.sequence.VoxelDimensions; import mpicbg.spim.io.IOFunctions; import net.imglib2.util.Util; import spim.fiji.plugin.queryXML.LoadParseQueryXML; import spim.fiji.plugin.util.GUIHelper; import spim.fiji.spimdata.SpimData2; import spim.fiji.spimdata.ViewSetupUtils; public class Specify_Calibration implements PlugIn { @Override public void run( final String arg0 ) { // ask for everything final LoadParseQueryXML result = new LoadParseQueryXML(); if ( !result.queryXML( "specifying calibration", true, true, true, true ) ) return; final SpimData2 data = result.getData(); final List< ViewId > viewIds = SpimData2.getAllViewIdsSorted( data, result.getViewSetupsToProcess(), result.getTimePointsToProcess() ); final ArrayList< Cal > calibrations = findCalibrations( data, viewIds ); final Cal maxCal = mostPresentCal( calibrations ); if ( !queryNewCal( calibrations, maxCal ) ) return; applyCal( maxCal, data, viewIds ); // save the xml SpimData2.saveXML( data, result.getXMLFileName(), result.getClusterExtension() ); } public static boolean queryNewCal( final ArrayList< Cal > calibrations, final Cal maxCal ) { final GenericDialog gd = new GenericDialog( "Define new calibration" ); gd.addNumericField( "Calibration_x", maxCal.getCal()[ 0 ], 40, 20, "" ); // ImageJ cuts of part of the number otherwise ((TextField)gd.getNumericFields().lastElement()).setText( "" + maxCal.getCal()[ 0 ] ); gd.addNumericField( "Calibration_y", maxCal.getCal()[ 1 ], 40, 20, "" ); // ImageJ cuts of part of the number otherwise ((TextField)gd.getNumericFields().lastElement()).setText( "" + maxCal.getCal()[ 1 ] ); gd.addNumericField( "Calibration_z", maxCal.getCal()[ 2 ], 40, 20, "" ); // ImageJ cuts of part of the number otherwise ((TextField)gd.getNumericFields().lastElement()).setText( "" + maxCal.getCal()[ 2 ] ); gd.addStringField( "Unit", maxCal.unit() ); if ( calibrations.size() > 1 ) gd.addMessage( "WARNING: Calibrations are not the same for all\n" + "view setups! All calibrations will be overwritten\n" + "for all view setups if defined here.", GUIHelper.mediumstatusfont, GUIHelper.warning ); gd.addMessage( "Note: These values will be applied to selected view\n" + "setups, existing registration are not affected and\n" + "will need to be recomputed if necessary.", GUIHelper.mediumstatusfont ); gd.showDialog(); if ( gd.wasCanceled() ) return false; maxCal.getCal()[ 0 ] = gd.getNextNumber(); maxCal.getCal()[ 1 ] = gd.getNextNumber(); maxCal.getCal()[ 2 ] = gd.getNextNumber(); maxCal.setUnit( gd.getNextString() ); return true; } // TODO: this should not be necessary, could be AbstractSpimData public static void applyCal( final Cal maxCal, final SpimData spimData, final List< ViewId > viewIds ) { // this is the same for all timepoints, we are just interested in the ViewSetup final TimePoint t = spimData.getSequenceDescription().getTimePoints().getTimePointsOrdered().get( 0 ); for ( final ViewId viewId : viewIds ) { if ( viewId.getTimePointId() != t.getId() ) continue; final ViewDescription desc = spimData.getSequenceDescription().getViewDescriptions().get( viewId ); final ViewSetup viewSetup = desc.getViewSetup(); viewSetup.setVoxelSize( new FinalVoxelDimensions( maxCal.unit(), maxCal.getCal()[ 0 ], maxCal.getCal()[ 1 ], maxCal.getCal()[ 2 ] ) ); } } public static ArrayList< Cal > findCalibrations( final AbstractSpimData< ? extends AbstractSequenceDescription< ?, ?, ? > > spimData, final List< ViewId > viewIds ) { // this is the same for all timepoints, we are just interested in the ViewSetup final TimePoint t = spimData.getSequenceDescription().getTimePoints().getTimePointsOrdered().get( 0 ); final ArrayList< Cal > calibrations = new ArrayList< Cal >(); for ( final ViewId viewId : viewIds ) { if ( viewId.getTimePointId() != t.getId() ) continue; final BasicViewDescription< ? > vd = spimData.getSequenceDescription().getViewDescriptions().get( viewId ); final BasicViewSetup vs = vd.getViewSetup(); final String name; if ( ViewSetup.class.isInstance( vs ) ) { name = "angle: " + ((ViewSetup)vs).getAngle().getName() + " channel: " + ((ViewSetup)vs).getChannel().getName() + " illum: " + ((ViewSetup)vs).getIllumination().getName() + ", present at timepoint: " + t.getName() + ": " + vd.isPresent(); } else { name = "viewsetup: " + vs.getId() + ", present at timepoint: " + t.getName() + ": " + vd.isPresent(); } // only consider voxelsizes as defined in the XML VoxelDimensions voxelSize = ViewSetupUtils.getVoxelSize( vs ); if ( voxelSize == null ) voxelSize = new FinalVoxelDimensions( "", new double[]{ 1, 1, 1 } ); final double x = voxelSize.dimension( 0 ); final double y = voxelSize.dimension( 1 ); final double z = voxelSize.dimension( 2 ); String unit = voxelSize.unit(); if ( unit == null ) unit = ""; IOFunctions.println( "cal: [" + x + ", " + y + ", " + z + "] " + unit + " -- " + name ); final Cal calTmp = new Cal( new double[]{ x, y, z }, unit ); boolean foundMatch = false; for ( int j = 0; j < calibrations.size() && !foundMatch; ++j ) { final Cal cal = calibrations.get( j ); if ( cal.equals( calTmp ) ) { cal.increaseCount(); foundMatch = true; } } if ( !foundMatch ) calibrations.add( calTmp ); } return calibrations; } public static Cal mostPresentCal( final Collection< Cal > calibrations ) { int max = 0; Cal maxCal = null; for ( final Cal cal : calibrations ) { if ( cal.getCount() > max ) { max = cal.getCount(); maxCal = cal; } } IOFunctions.println( "Number of calibrations: " + calibrations.size() ); IOFunctions.println( "Calibration most often present: " + Util.printCoordinates( maxCal.getCal() ) + " (" + maxCal.getCount() + " times)" ); return maxCal; } public static class Cal { final double[] cal; int count; String unit; public Cal( final double[] cal, final String unit ) { this.cal = cal; this.count = 1; this.unit = unit; } public void increaseCount() { ++count; } public int getCount() { return count; } public double[] getCal() { return cal; } public String unit() { return unit; } public void setUnit( final String unit ) { this.unit = unit; } @Override public boolean equals( final Object o ) { if ( o instanceof Cal ) { final Cal c2 = (Cal)o; if ( c2.cal.length != this.cal.length ) return false; else { for ( int d = 0; d < cal.length; ++d ) if ( c2.cal[ d ] != cal[ d ] ) return false; return true; } } else return false; } } public static void main( String[] args ) { IOFunctions.printIJLog = true; new ImageJ(); new Specify_Calibration().run( null ); } }