/*- * #%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.datasetmanager; import ij.ImagePlus; import ij.io.Opener; import java.io.BufferedReader; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import spim.fiji.ImgLib2Temp.ValuePair; import spim.fiji.ImgLib2Temp.Pair; import mpicbg.spim.io.IOFunctions; import mpicbg.spim.io.TextFileAccess; public class DHMMetaData { File directory; double calX, calY, calZ; String calUnit; boolean compareAllSizes; String stackDir = null; String ampDir = null; String phaseDir = null; String holoDir = null; String timestampFile = null; String extension = null; int ampChannelId = 0; int phaseChannelId = 1; int width = -1; int height = -1; List< String > zPlanes; List< String > timepoints; public DHMMetaData( final File directory, final double calX, final double calY, final double calZ, final String calUnit, final boolean compareAllSizes ) { this.directory = directory; this.calX = calX; this.calY = calY; this.calZ = calZ; this.calUnit = calUnit; this.compareAllSizes = compareAllSizes; } public boolean loadMetaData() { if ( !checkIntegrity( directory ) ) return false; IOFunctions.println( "Stack directory: ./" + stackDir ); IOFunctions.println( "Amplitude directory: ./" + stackDir + "/" + ampDir ); IOFunctions.println( "Phase directory: ./" + stackDir + "/" + phaseDir ); if ( !parseTimestamps( directory, timestampFile ) ) IOFunctions.println( "Failed to parse timestamp file." ); if ( !getTimestampsAndZPlanes( compareAllSizes ) ) return false; IOFunctions.println( "Final timepoints available for all zPlanes in Phase & Amplitude:" ); for ( final String t : timepoints ) IOFunctions.println( t ); IOFunctions.println( "Final zPlanes available in Phase & Amplitude:" ); for ( final String z : zPlanes ) IOFunctions.println( z ); IOFunctions.println( "imgX: " + width + "px" ); IOFunctions.println( "imgY: " + height + "px" ); IOFunctions.println( "imgZ: " + getDepth() + "px" ); IOFunctions.println( "calX: " + calX + " " + calUnit ); IOFunctions.println( "calY: " + calY + " " + calUnit ); IOFunctions.println( "calZ: " + calZ + " " + calUnit ); IOFunctions.println( "anisotropy: " + calZ / Math.min( calX, calY ) + "X "); IOFunctions.println( "image plane extension: " + extension ); return true; } public File getDir() { return directory; } public String getStackDir() { return stackDir; } public String getAmplitudeDir() { return ampDir; } public String getPhaseDir() { return phaseDir; } public List< String > getZPlanes() { return zPlanes; } public List< String > getTimepoints() { return timepoints; } public int getAmpChannelId() { return ampChannelId; } public int getPhaseChannelId() { return phaseChannelId; } public int getWidth() { return width; } public int getHeight() { return height; } public int getDepth() { return zPlanes.size(); } public String getExt() { return extension; } /** * Go through the directories and make sure all timestamps are present for all ampliude/phase-stacks * @param compareAllSizes - open all 2d-planes and make sure the dimensions match? * @return */ public boolean getTimestampsAndZPlanes( final boolean compareAllSizes ) { final File ampDir = new File( new File( directory.getAbsolutePath(), stackDir ).getAbsolutePath(), this.ampDir ); final File phaseDir = new File( new File( directory.getAbsolutePath(), stackDir ).getAbsolutePath(), this.phaseDir ); if ( timepoints == null ) { IOFunctions.println( "timestamps not know, loading from amplitude directory at z=0.00" ); final Pair< List< String >, String > tps = loadTimepoints( new File( ampDir.getAbsolutePath(), "0.00" ) ); if ( tps == null ) return false; else { timepoints = tps.getA(); IOFunctions.println( "Following timepoints found:" ); for ( final String t : timepoints ) IOFunctions.println( t ); IOFunctions.println( "Extension: " + tps.getB() ); } } final List< File > dirs = new ArrayList< File >(); dirs.add( ampDir ); dirs.add( phaseDir ); final HashMap< String, Integer > zPlanes = new HashMap< String, Integer >(); this.width = -1; this.height = -1; this.extension = null; final Opener opener = new Opener(); for ( final File dir : dirs ) { for ( final String d : dir.list() ) { final File planeDir = new File( dir, d ); if ( planeDir.exists() && planeDir.isDirectory() && d.matches( "-?[0-9]+\\.[0-9]+" ) ) { final Pair< List< String >, String > tps = loadTimepoints( planeDir ); if ( tps == null ) return false; if ( width == -1 && height == -1 ) { final File imgF = new File( planeDir.getAbsolutePath(), tps.getA().get( 0 ) + tps.getB() ); final ImagePlus imp = opener.openImage( imgF.getAbsolutePath() ); width = imp.getWidth(); height = imp.getHeight(); imp.close(); IOFunctions.println( "Dimensions of plane image loaded from '" + imgF + "':" + width + "x" + height + "px." ); } if ( compareAllSizes ) { for ( final String imgN : tps.getA() ) { final File imgF = new File( planeDir.getAbsolutePath(), imgN + tps.getB() ); final ImagePlus imp = opener.openImage( imgF.getAbsolutePath() ); int w = imp.getWidth(); int h = imp.getHeight(); imp.close(); if ( w != width || h != height ) { IOFunctions.println( "Dimensions for image '" + imgF + "' do not match: " + w + "x" + h + "px, before was " + width + "x" + height + "px. Stopping." ); return false; } } } if ( this.extension == null ) this.extension = tps.getB(); if ( !this.extension.equals( tps.getB() ) ) { IOFunctions.println( "Extension of filenames is not consistent. Was before '" + extension + "', now is '" + tps.getB() + "'. Stopping" ); return false; } if ( tps.getA().size() != timepoints.size() ) IOFunctions.println( "Different amount of timepoints (" + tps.getA().size() + ") for dir: " + planeDir ); final int size = this.timepoints.size(); this.timepoints = commonStrings( this.timepoints, tps.getA() ); if ( size != timepoints.size() ) IOFunctions.println( "Common amount of timepoints is now: " + timepoints.size() ); if ( zPlanes.containsKey( d ) ) { int i = zPlanes.get( d ); zPlanes.put( d, i + 1 ); } else { zPlanes.put( d, 1 ); } } } } this.zPlanes = new ArrayList< String >(); for ( final String z : zPlanes.keySet() ) { if ( zPlanes.get( z ) != 2 ) IOFunctions.println( "zPlane '' exists " + zPlanes.get( z ) + " times, this is wrong!" ); else this.zPlanes.add( z ); } // sort zPlanes by number value Collections.sort( this.zPlanes, new Comparator< String >() { @Override public int compare( final String o1, final String o2 ) { final double d = Double.parseDouble( o1 ) - Double.parseDouble( o2 ); if ( d < 0 ) return -1; else if ( d > 0 ) return 1; else return 0; } } ); return true; } public static List< String > commonStrings( final List< String > listA, final List< String > listB ) { final Set< String > setA = new HashSet< String >(); final Set< String > setB = new HashSet< String >(); final Set< String > setC = new HashSet< String >(); setA.addAll( listA ); setB.addAll( listB ); for ( final String a : listA ) if ( setB.contains( a ) ) setC.add( a ); for ( final String b : listB ) if ( setA.contains( b ) ) setC.add( b ); final ArrayList< String > listC = new ArrayList< String >(); listC.addAll( setC ); Collections.sort( listC ); return listC; } public static Pair< List< String >, String > loadTimepoints ( final File dataDir ) { if ( !dataDir.exists() ) { IOFunctions.println( dataDir.getAbsolutePath() + " does not exist" ); return null; } final ArrayList< String > list = new ArrayList< String >(); final String regex = "^[0-9]+\\.[tifTIF]+"; final String[] files = dataDir.list(); Arrays.sort( files ); String extension = null; for ( final String t : files ) if ( t.matches( regex ) ) { list.add( t.split( "\\." )[ 0 ] ); String ext = t.substring( t.indexOf( "." ), t.length() ); if ( extension == null ) { extension = ext; } else if ( !ext.equals( extension ) ) { IOFunctions.println( "Extension of filenames is not consistent. Was before '" + extension + "', now is '" + ext + "'. Stopping" ); return null; } } return new ValuePair< List< String >, String >( list, extension ); } public boolean parseTimestamps( final File directory, final String timestampFile ) { if ( timestampFile == null ) return false; final File t = new File( directory.getAbsolutePath(), timestampFile ); if ( !t.exists() ) return false; final BufferedReader in = TextFileAccess.openFileRead( t ); try { this.timepoints = new ArrayList< String >(); IOFunctions.println( "Following timepoints specified in timestamps.txt:" ); while ( in.ready() ) { String s = in.readLine().trim(); if ( s.length() > 0 ) { final String[] entries = s.split( " " ); timepoints.add( entries[ 0 ] ); IOFunctions.println( timepoints.get( timepoints.size() - 1 ) ); } } } catch ( Exception e ) { e.printStackTrace(); timepoints = null; return false; } return true; } public boolean checkIntegrity( final File directory ) { if ( !directory.exists() ) { IOFunctions.println( "File '" + directory.getAbsolutePath() + "' does not exist. Stopping" ); return false; } else { IOFunctions.println( "Investigating directory '" + directory.getAbsolutePath() + "'." ); } String[] files = directory.list(); for ( final String f : files ) { if ( f.toLowerCase().equals( "stack" ) ) stackDir = f; else if ( f.toLowerCase().equals( "holograms" ) ) holoDir = f; else if ( f.toLowerCase().equals( "timestamps.txt" ) ) timestampFile = f; } if ( holoDir == null ) IOFunctions.println( "WARNING: Holograms-Directory does not exist. Continuing." ); if ( timestampFile == null ) IOFunctions.println( "WARNING: Timestamps.txt file missing. Continuing." ); if ( stackDir == null ) { IOFunctions.println( "Stack-Directory does not exist. Stopping" ); return false; } else { files = new File( directory.getAbsolutePath(), stackDir ).list(); for ( final String f : files ) { if ( f.toLowerCase().equals( "amplitude" ) ) ampDir = f; else if ( f.toLowerCase().equals( "phase" ) ) phaseDir = f; } if ( ampDir == null ) { IOFunctions.println( "Amplitude-Stack-Directory does not exist. Stopping" ); return false; } if ( phaseDir == null ) { IOFunctions.println( "Phase-Stack-Directory does not exist. Stopping" ); return false; } } return true; } public static void main( String[] args ) { //String s = "00000.TIF"; //System.out.println( s.matches( "^[0-9]+\\.[tifTIF]+" ) ); new DHMMetaData( new File( "/Users/preibischs/Downloads/2015.07.10 17-25_Ser_r" ), DHM.defaulCalX, DHM.defaulCalY, DHM.defaulCalZ, DHM.defaulCalUnit, false ).loadMetaData(); } }