diff --git a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinition.java b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinition.java index b5155d91..79022d45 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinition.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinition.java @@ -115,6 +115,7 @@ import net.preibisch.mvrecon.fiji.spimdata.imgloaders.LegacyFileMapImgLoaderLOCI; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapGettable; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapImgLoaderLOCI2; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; import net.preibisch.mvrecon.fiji.spimdata.intensityadjust.IntensityAdjustments; import net.preibisch.mvrecon.fiji.spimdata.interestpoints.ViewInterestPoints; import net.preibisch.mvrecon.fiji.spimdata.pointspreadfunctions.PointSpreadFunctions; @@ -443,18 +444,18 @@ public boolean test(Path t) private static SpimData2 buildSpimData( FileListViewDetectionState state, boolean withVirtualLoader ) { - - //final Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > fm = tileIdxMap; + + //final Map< Integer, List< FileMapEntry > > fm = tileIdxMap; //fm.forEach( (k,v ) -> {System.out.println( k ); v.forEach( p -> {System.out.print(p.getA() + ""); System.out.print(p.getB().getA().toString() + " "); System.out.println(p.getB().getB().toString());} );}); - - - Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > tpIdxMap = state.getIdMap().get( TimePoint.class ); - Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > channelIdxMap = state.getIdMap().get( Channel.class ); - Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > illumIdxMap = state.getIdMap().get( Illumination.class ); - Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > tileIdxMap = state.getIdMap().get( Tile.class ); - Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > angleIdxMap = state.getIdMap().get( Angle.class ); - - + + + Map< Integer, List< FileMapEntry > > tpIdxMap = state.getIdMap().get( TimePoint.class ); + Map< Integer, List< FileMapEntry > > channelIdxMap = state.getIdMap().get( Channel.class ); + Map< Integer, List< FileMapEntry > > illumIdxMap = state.getIdMap().get( Illumination.class ); + Map< Integer, List< FileMapEntry > > tileIdxMap = state.getIdMap().get( Tile.class ); + Map< Integer, List< FileMapEntry > > angleIdxMap = state.getIdMap().get( Angle.class ); + + List timepointIndexList = new ArrayList<>(tpIdxMap.keySet()); List channelIndexList = new ArrayList<>(channelIdxMap.keySet()); List illuminationIndexList = new ArrayList<>(illumIdxMap.keySet()); @@ -477,7 +478,7 @@ private static SpimData2 buildSpimData( FileListViewDetectionState state, boolea List missingViewIds = new ArrayList<>(); List timePoints = new ArrayList<>(); - HashMap, Pair>> ViewIDfileMap = new HashMap<>(); + Map< Pair< Integer, Integer >, FileMapEntry > ViewIDfileMap = new HashMap<>(); Integer viewSetupId = 0; for (Integer c = 0; c < nChannels; c++) for (Integer i = 0; i < nIlluminations; i++) @@ -488,8 +489,8 @@ private static SpimData2 buildSpimData( FileListViewDetectionState state, boolea boolean addedViewSetup = false; for (Integer tp = 0; tp < nTimepoints; tp++) { - - List< Pair< File, Pair< Integer, Integer > > > viewList; + + List< FileMapEntry > viewList; viewList = FileListDatasetDefinitionUtil.listIntersect( channelIdxMap.get( channelIndexList.get( c ) ), angleIdxMap.get( angleIndexList.get( a ) ) ); viewList = FileListDatasetDefinitionUtil.listIntersect( viewList, tileIdxMap.get( tileIndexList.get( ti ) ) ); viewList = FileListDatasetDefinitionUtil.listIntersect( viewList, illumIdxMap.get( illuminationIndexList.get( i ) ) ); @@ -520,8 +521,8 @@ else if (viewList.size() > 1) IOFunctions.println( "Error: more than one View: ch" + c +" a"+ a + " ti" + ti + " tp"+ tp + " i" + i ); else { - IOFunctions.println( "Found View: ch" + c +" a"+ a + " ti" + ti + " tp"+ tp + " i" + i + " in file " + viewList.get( 0 ).getA().getAbsolutePath()); - + IOFunctions.println( "Found View: ch" + c +" a"+ a + " ti" + ti + " tp"+ tp + " i" + i + " in file " + viewList.get( 0 ).file().getAbsolutePath()); + TimePoint tpI = new TimePoint( tpId ); if (!timePoints.contains( tpI )) timePoints.add( tpI ); @@ -610,8 +611,8 @@ else if ( aInfoI.axis == 2 ) SequenceDescription sd = new SequenceDescription( new TimePoints( timePoints ), viewSetups , null, new MissingViews( missingViewIds )); - - HashMap, Pair>> fileMap = new HashMap<>(); + + Map< BasicViewDescription< ? >, FileMapEntry > fileMap = new HashMap<>(); for (Pair k : ViewIDfileMap.keySet()) { System.out.println( k.getA() + " " + k.getB() ); @@ -982,7 +983,7 @@ else if (choice.equals( Z_VARIABLE_CHOICE )) final double calZ = gd.getNextNumber(); final String calUnit = gd.getNextString(); - for (final Pair< File, Pair< Integer, Integer > > key : state.getDimensionMap().keySet()) + for (final FileMapEntry key : state.getDimensionMap().keySet()) { final Pair< Dimensions, VoxelDimensions > pairOld = state.getDimensionMap().get( key ); final Pair< Dimensions, VoxelDimensions > pairNew = new ValuePair< Dimensions, VoxelDimensions >( pairOld.getA(), new FinalVoxelDimensions( calUnit, calX, calY, calZ ) ); @@ -1093,7 +1094,7 @@ else if (choice.equals( Z_VARIABLE_CHOICE )) ((FileMapGettable)data.getSequenceDescription().getImgLoader() ).getFileMap().values().stream().forEach( p -> { - filenames.add( p.getA().getAbsolutePath()); + filenames.add( p.file().getAbsolutePath()); }); final File prefixPath; if (filenames.size() > 1) diff --git a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinitionUtil.java b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinitionUtil.java index 613de140..45c90ab5 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinitionUtil.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListDatasetDefinitionUtil.java @@ -42,7 +42,6 @@ import java.util.regex.Matcher; import java.util.stream.Collectors; -import ij.IJ; import ij.io.OpenDialog; import loci.formats.FormatException; import loci.formats.IFormatReader; @@ -69,6 +68,7 @@ import net.preibisch.mvrecon.fiji.datasetmanager.metadatarefinement.NikonND2TileOrAngleRefiner; import net.preibisch.mvrecon.fiji.datasetmanager.metadatarefinement.TileOrAngleRefiner; import net.preibisch.mvrecon.fiji.datasetmanager.patterndetector.FilenamePatternDetector; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.util.BioformatsReaderUtils; import ome.units.quantity.Length; @@ -565,21 +565,21 @@ public static void resolveAmbiguity(Map, CheckResult> ch public static void groupZPlanes(FileListViewDetectionState state, FilenamePatternDetector patternDetector, List variablesToUse) { - final Map< Pair< File, Pair< Integer, Integer > >, Pair< Dimensions, VoxelDimensions > > dimensionMap = state.getDimensionMap(); + final Map< FileMapEntry, Pair< Dimensions, VoxelDimensions > > dimensionMap = state.getDimensionMap(); for (final Class cl: state.getIdMap().keySet()) { - final Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > idMapForClass = state.getIdMap().get( cl ); - for (final List< Pair< File, Pair< Integer, Integer > > > fileList : idMapForClass.values()) + final Map< Integer, List< FileMapEntry > > idMapForClass = state.getIdMap().get( cl ); + for (final List< FileMapEntry > fileList : idMapForClass.values()) { // construct Map (invariant idxes, series, channel) -> (varying idxes) - final Map< Pair, Pair>, List>> zGroupedMap = new HashMap<>(); - final Map< Pair, Pair>, Pair< Dimensions, VoxelDimensions >> dimensionGroupedMap = new HashMap<>(); - for (final Pair< File, Pair< Integer, Integer > > file : fileList) + final Map< Pair< List< Integer >, Pair< Integer, Integer > >, List< List< Integer > > > zGroupedMap = new HashMap<>(); + final Map< Pair< List< Integer >, Pair< Integer, Integer > >, Pair< Dimensions, VoxelDimensions > > dimensionGroupedMap = new HashMap<>(); + for (final FileMapEntry file : fileList) { - final Pair< Integer, Integer > seriesChannel = file.getB(); + final Pair< Integer, Integer > seriesChannel = new ValuePair<>( file.series(), file.channel() ); final List variables = new ArrayList<>(); final List invariants = new ArrayList<>(); - final Matcher m = patternDetector.getPatternAsRegex().matcher( file.getA().getAbsolutePath() ); + final Matcher m = patternDetector.getPatternAsRegex().matcher( file.file().getAbsolutePath() ); if (!m.matches()) IOFunctions.printErr( "ERROR grouping z planes" ); @@ -626,8 +626,9 @@ public static void groupZPlanes(FileListViewDetectionState state, FilenamePatter // construct pattern final String patternPath = getPatternFile( patternDetector, variablesToUse, invariants, v ); System.out.println( patternPath ); - fileList.add( new ValuePair<>( new File( patternPath ), k.getB() ) ); - dimensionMap.put( new ValuePair<>( new File( patternPath ), k.getB() ), dimensionGroupedMap.get( k ) ); + final FileMapEntry fileMapEntry = new FileMapEntry( new File( patternPath ), k.getB().getA(), k.getB().getB() ); + fileList.add( fileMapEntry ); + dimensionMap.put( fileMapEntry, dimensionGroupedMap.get( k ) ); }); } } @@ -684,8 +685,8 @@ public static String getPatternFile(FilenamePatternDetector patternDetector, Lis if ( singleEntityPerFile && fileVariableToUse.get( cl ).size() > 0 ) { - Pair< Map< Integer, Object >, Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > > expandedMap; - + Pair< Map< Integer, Object >, Map< Integer, List< FileMapEntry > > > expandedMap; + if (state.getGroupedFormat()) { Map< String, Pair< File, Integer > > groupUsageMap = state.getGroupUsageMap(); @@ -709,10 +710,10 @@ else if ( singleEntityPerFile ) // TODO: this should probably be fixed upstream // At the moment, all instances of this attribute will get id 0 // NB: this throws away metadata - final ArrayList< Pair< File, Pair< Integer, Integer > > > allViews = state.getAccumulateMap( cl ).values().stream().collect( - ArrayList>>::new, - (a,b) -> a.addAll(b), - (a,b) -> a.addAll(b) ); + final ArrayList< FileMapEntry > allViews = state.getAccumulateMap( cl ).values().stream().collect( + ArrayList::new, + ArrayList::addAll, + ArrayList::addAll ); state.getIdMap().get( cl ).put( 0, allViews ); } @@ -726,7 +727,7 @@ else if ( state.getMultiplicityMap().get( cl ) == CheckResult.MULTIPLE_INDEXED ) else if ( state.getMultiplicityMap().get( cl ) == CheckResult.MUlTIPLE_NAMED ) { - Pair< Map< Integer, Object >, Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > > resortMapNamed = resortMapNamed( + Pair< Map< Integer, Object >, Map< Integer, List< FileMapEntry > > > resortMapNamed = resortMapNamed( state.getAccumulateMap( cl ) ); state.getDetailMap().get( cl ).putAll( resortMapNamed.getA() ); state.getIdMap().get( cl ).putAll( resortMapNamed.getB() ); @@ -735,24 +736,26 @@ else if ( state.getMultiplicityMap().get( cl ) == CheckResult.MUlTIPLE_NAMED ) } } - - public static Pair, Map>>>> expandMapSingleFromFile(Map>>> map, FilenamePatternDetector det, List patternIdx) + + public static < T > Pair< Map< Integer, T >, Map< Integer, List< FileMapEntry > > > expandMapSingleFromFile( + Map< T, List< FileMapEntry > > map, + FilenamePatternDetector det, + List< Integer > patternIdx ) { - Map>>> res = new HashMap<>(); + Map> res = new HashMap<>(); Map res2 = new HashMap<>(); - SortedMap< Pair< File, Pair< Integer, Integer > >, T > invertedMap = invertMapSortValue( map ); - - // + SortedMap< FileMapEntry, T > invertedMap = invertMapSortValue( map ); + Map, Integer> multiIdxMap = new HashMap<>(); - - for (Pair< File, Pair< Integer, Integer > > fileInfo : invertedMap.keySet()) + + for (FileMapEntry fileInfo : invertedMap.keySet()) { int id = -1; T attribute = invertedMap.get( fileInfo ); //System.out.println( fileInfo.getA().getAbsolutePath() ); - - Matcher m = det.getPatternAsRegex().matcher( fileInfo.getA().getAbsolutePath() ); - + + Matcher m = det.getPatternAsRegex().matcher( fileInfo.file().getAbsolutePath() ); + // we have one numerical group describing this attribute -> use it as id if (patternIdx.size() == 1) { @@ -783,24 +786,24 @@ public static Pair, Map, Map>>> >( res2, res ); - + + return new ValuePair<>( res2, res ); } - - public static Pair, Map>>>> expandMapSingleFromFileGroupedFormat( - Map>>> map, - FilenamePatternDetector det, - List patternIdx, - Map< String, Pair< File, Integer > > groupUsageMap) + + public static < T > Pair< Map< Integer, T >, Map< Integer, List< FileMapEntry > > > expandMapSingleFromFileGroupedFormat( + Map< T, List< FileMapEntry > > map, + FilenamePatternDetector det, + List< Integer > patternIdx, + Map< String, Pair< File, Integer > > groupUsageMap ) { - Map>>> res = new HashMap<>(); + Map< Integer, List< FileMapEntry > > res = new HashMap<>(); Map res2 = new HashMap<>(); - SortedMap< Pair< File, Pair< Integer, Integer > >, T > invertedMap = invertMapSortValue( map ); - - // + SortedMap< FileMapEntry, T > invertedMap = invertMapSortValue( map ); + + // Map, Integer> multiIdxMap = new HashMap<>(); - - for (Pair< File, Pair< Integer, Integer > > fileInfo : invertedMap.keySet()) + + for (FileMapEntry fileInfo : invertedMap.keySet()) { int id = -1; T attribute = invertedMap.get( fileInfo ); @@ -811,7 +814,7 @@ public static Pair, Map > e : groupUsageMap.entrySet()) { - if (new ValuePair<>( fileInfo.getA(), fileInfo.getB().getA() ).equals( e.getValue() )) + if (new ValuePair<>( fileInfo.file(), fileInfo.series() ).equals( e.getValue() )) seriesFile = e.getKey(); } @@ -848,22 +851,23 @@ public static Pair, Map() ); res.get( id ).add( fileInfo ); } - return new ValuePair< Map, Map>>> >( res2, res ); - + return new ValuePair<>( res2, res ); + } - - public static Pair, Map>>>> resortMapNamed(Map>>> map) + + public static < T > Pair< Map< Integer, T >, Map< Integer, List< FileMapEntry > > > resortMapNamed( + Map< T, List< FileMapEntry > > map ) { - - Map>>> res = new HashMap<>(); - Map res2 = new HashMap<>(); - SortedMap< Pair< File, Pair< Integer, Integer > >, T > invertedMap = invertMapSortValue( map ); + + Map< Integer, List< FileMapEntry > > res = new HashMap<>(); + Map< Integer, T > res2 = new HashMap<>(); + SortedMap< FileMapEntry, T > invertedMap = invertMapSortValue( map ); int maxId = 0; - for (Pair< File, Pair< Integer, Integer > > fileInfo : invertedMap.keySet()) + for ( FileMapEntry fileInfo : invertedMap.keySet() ) { - int id= 0; + int id = 0; T attribute = invertedMap.get( fileInfo ); - if (!res2.values().contains( attribute )) + if ( !res2.values().contains( attribute ) ) { res2.put( maxId, attribute ); id = maxId; @@ -871,38 +875,40 @@ public static Pair, Map() ); res.get( id ).add( fileInfo ); } - return new ValuePair< Map, Map>>> >( res2, res ); + return new ValuePair<>( res2, res ); } - - - public static Map>>> expandMapIndexed(Map>>> map, boolean useSeries) + + + public static < T > Map< Integer, List< FileMapEntry > > expandMapIndexed( + Map< T, List< FileMapEntry > > map, boolean useSeries ) { - Map>>> res = new HashMap<>(); - SortedMap< Pair< File, Pair< Integer, Integer > >, T > invertedMap = invertMapSortValue( map ); - for (Pair< File, Pair< Integer, Integer > > fileInfo : invertedMap.keySet()) + Map< Integer, List< FileMapEntry > > res = new HashMap<>(); + SortedMap< FileMapEntry, T > invertedMap = invertMapSortValue( map ); + for ( FileMapEntry fileInfo : invertedMap.keySet() ) { - int id = useSeries ? fileInfo.getB().getA() : fileInfo.getB().getB(); + int id = useSeries ? fileInfo.series() : fileInfo.channel(); if (!res.containsKey( id )) res.put( id, new ArrayList<>() ); res.get( id ).add( fileInfo ); } return res; } - - public static Map>>> expandTimePointMapIndexed(Map>>> map) + + public static < T > Map< Integer, List< FileMapEntry > > expandTimePointMapIndexed( + Map< T, List< FileMapEntry > > map ) { - Map>>> res = new HashMap<>(); - SortedMap< Pair< File, Pair< Integer, Integer > >, T > invertedMap = invertMapSortValue( map ); - for (Pair< File, Pair< Integer, Integer > > fileInfo : invertedMap.keySet()) + Map< Integer, List< FileMapEntry > > res = new HashMap<>(); + SortedMap< FileMapEntry, T > invertedMap = invertMapSortValue( map ); + for ( FileMapEntry fileInfo : invertedMap.keySet() ) { // TODO: can we get around this dirty cast? Integer numTP = (Integer) invertedMap.get( fileInfo ); @@ -915,32 +921,32 @@ public static Map>>> expan } return res; } - - - public static SortedMap>, T> invertMapSortValue(Map>>> map ) + + + public static < T > SortedMap< FileMapEntry, T > invertMapSortValue( Map< T, List< FileMapEntry > > map ) { - - SortedMap>, T> res = new TreeMap>, T>( new Comparator< Pair> >() + + SortedMap< FileMapEntry, T > res = new TreeMap<>( new Comparator< FileMapEntry >() { @Override - public int compare(Pair< File, Pair< Integer, Integer > > o1, Pair< File, Pair< Integer, Integer > > o2) + public int compare(FileMapEntry o1, FileMapEntry o2) { - int filecompare = o1.getA().getAbsolutePath().compareTo( o2.getA().getAbsolutePath() ) ; + int filecompare = o1.file().getAbsolutePath().compareTo( o2.file().getAbsolutePath() ) ; if (filecompare != 0) return filecompare; - - int seriescompare = o1.getB().getA().compareTo( o2.getB().getA() ); + + int seriescompare = Integer.compare( o1.series(), o2.series() ); if (seriescompare != 0) return seriescompare; - - return o1.getB().getB().compareTo( o2.getB().getB() ); + + return Integer.compare( o1.channel(), o2.channel() ); } } ); - + for (T key : map.keySet()) { - for (Pair> vI : map.get( key )) + for (FileMapEntry vI : map.get( key )) { //System.out.println( vI.getB().getA() + "" + vI.getB().getB() ); //System.out.println( key ); @@ -948,10 +954,10 @@ public int compare(Pair< File, Pair< Integer, Integer > > o1, Pair< File, Pair< } } //System.out.println( res.size() ); - return res; + return res; } - - public static void detectDimensionsInFile(File file, Map>, Pair> dimensionMaps, ImageReader reader) + + public static void detectDimensionsInFile( File file, Map< FileMapEntry, Pair< Dimensions, VoxelDimensions > > dimensionMaps, ImageReader reader ) { //System.out.println( file ); @@ -1032,11 +1038,11 @@ public static void detectDimensionsInFile(File file, Map> key = new ValuePair< File, Pair >( currentFile, new ValuePair< Integer, Integer >( i, j ) ); - dimensionMaps.put( key, new ValuePair< Dimensions, VoxelDimensions >( finalDimensions, finalVoxelDimensions ) ); + { + FileMapEntry key = new FileMapEntry( currentFile, i, j ); + dimensionMaps.put( key, new ValuePair<>( finalDimensions, finalVoxelDimensions ) ); } - + } reader.close(); @@ -1156,8 +1162,10 @@ public static void detectViewsInFile(final File file, // map to tileMap and angleMap Pair< Map< TileInfo, List< Pair< Integer, Integer > > >, Map< AngleInfo, List< Pair< Integer, Integer > > > > mapTilesAngles = mapTilesAndAnglesToSeries( predictTilesAndAngles ); - infoMap.put( Tile.class, mapTilesAngles.getA()); - infoMap.put( Angle.class, mapTilesAngles.getB()); + final Map< TileInfo, List< Pair< Integer, Integer > > > tileMap = mapTilesAngles.getA(); + final Map< AngleInfo, List< Pair< Integer, Integer > > > angleMap = mapTilesAngles.getB(); + infoMap.put( Tile.class, tileMap ); + infoMap.put( Angle.class, angleMap ); // predict and map timepoints, channels, illuminations List< Pair< Integer, List< ChannelOrIlluminationInfo > > > predictTPChannelsIllum = predictTimepointsChannelsAndIllums( reader ); @@ -1174,18 +1182,14 @@ public static void detectViewsInFile(final File file, multiplicity.put( Illumination.class, checkMultiplicity( infoMap.get( Illumination.class ) )); // make Maps TileInfo -> Series (is TileInfo -> (Series, Channel) before) - Map< ? extends Object, List< Integer > > tileSeriesMap = infoMap.get( Tile.class ).entrySet().stream().collect( - Collectors.toMap( - (Entry< ? extends Object, List< Pair< Integer, Integer > > > e) -> e.getKey(), - (Entry< ? extends Object, List< Pair< Integer, Integer > > > e) -> - new ArrayList<>(e.getValue().stream().map(p -> p.getA()).collect(Collectors.toSet()))) ); + Map< TileInfo, List< Integer > > tileSeriesMap = tileMap.entrySet().stream().collect( + Collectors.toMap( Entry::getKey, + e -> e.getValue().stream().map( Pair::getA ).distinct().collect( Collectors.toList() ) ) ); // same but for Angles - Map< ? extends Object, List< Integer > > angleSeriesMap = infoMap.get( Angle.class ).entrySet().stream().collect( - Collectors.toMap( - (Entry< ? extends Object, List< Pair< Integer, Integer > > > e) -> e.getKey(), - (Entry< ? extends Object, List< Pair< Integer, Integer > > > e) -> - new ArrayList<>(e.getValue().stream().map(p -> p.getA()).collect(Collectors.toSet()))) ); + Map< AngleInfo, List< Integer > > angleSeriesMap = angleMap.entrySet().stream().collect( + Collectors.toMap( Entry::getKey, + e -> e.getValue().stream().map( Pair::getA ).distinct().collect( Collectors.toList() ) ) ); multiplicity.put( Angle.class, checkMultiplicity( angleSeriesMap )); multiplicity.put( Tile.class, checkMultiplicity( tileSeriesMap)); @@ -1233,7 +1237,8 @@ else if (tileMultiplicity == CheckResult.MUlTIPLE_NAMED && angleMultiplicity == { if (!state.getAccumulateMap(cl).containsKey( id )) state.getAccumulateMap(cl).put( id, new ArrayList<>() ); - infoMap.get( cl ).get( id ).forEach( series -> state.getAccumulateMap(cl).get( id ).add( new ValuePair< File, Pair< Integer, Integer > >( currentFile, series ) ) ); + infoMap.get( cl ).get( id ).forEach( series -> state.getAccumulateMap(cl).get( id ).add( + new FileMapEntry( currentFile, series.getA(), series.getB() ) ) ); } } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListViewDetectionState.java b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListViewDetectionState.java index 75828100..f1fa55b6 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListViewDetectionState.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/datasetmanager/FileListViewDetectionState.java @@ -23,15 +23,10 @@ package net.preibisch.mvrecon.fiji.datasetmanager; import java.io.File; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.SortedMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.security.auth.Destroyable; import mpicbg.spim.data.generic.base.Entity; import mpicbg.spim.data.sequence.Angle; @@ -43,10 +38,8 @@ import net.imglib2.Dimensions; import net.imglib2.util.Pair; import net.imglib2.util.ValuePair; -import net.preibisch.mvrecon.fiji.datasetmanager.FileListDatasetDefinitionUtil.AngleInfo; -import net.preibisch.mvrecon.fiji.datasetmanager.FileListDatasetDefinitionUtil.ChannelInfo; import net.preibisch.mvrecon.fiji.datasetmanager.FileListDatasetDefinitionUtil.CheckResult; -import net.preibisch.mvrecon.fiji.datasetmanager.FileListDatasetDefinitionUtil.TileInfo; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; public class FileListViewDetectionState { @@ -55,19 +48,19 @@ public class FileListViewDetectionState Boolean groupedFormat; Boolean wasZGrouped; - Map, FileListDatasetDefinitionUtil.CheckResult> multiplicityMap; - Map, Map>>>> accumulativeMap; - Map, Map< Integer, List< Pair< File, Pair< Integer, Integer > > > >> idMap; - Map, Map< Integer, Object>> detailMap; + Map< Class< ? extends Entity >, FileListDatasetDefinitionUtil.CheckResult > multiplicityMap; + Map< Class< ? extends Entity >, Map< Object, List< FileMapEntry > > > accumulativeMap; + Map< Class< ? extends Entity >, Map< Integer, List< FileMapEntry > > > idMap; + Map< Class< ? extends Entity >, Map< Integer, Object > > detailMap; - Map>, Pair> dimensionMap; - Map> groupUsageMap; + Map< FileMapEntry, Pair< Dimensions, VoxelDimensions > > dimensionMap; + Map< String, Pair< File, Integer > > groupUsageMap; public FileListViewDetectionState() { - multiplicityMap = new HashMap<>(); - accumulativeMap = new HashMap<>(); - idMap = new HashMap<>(); + multiplicityMap = new HashMap<>(); + accumulativeMap = new HashMap<>(); + idMap = new HashMap<>(); detailMap = new HashMap<>(); groupUsageMap = new HashMap<>(); @@ -97,12 +90,12 @@ public static Pair< Integer, Integer > getMinMaxNumChannelsIndexed(final FileLis if ( state.accumulativeMap.get( Channel.class ).size() < 1 ) return null; - final List< Pair< File, Pair< Integer, Integer > > > channelSources = state.accumulativeMap.get( Channel.class ) + final List< FileMapEntry > channelSources = state.accumulativeMap.get( Channel.class ) .values().iterator().next(); final Map< Pair< File, Integer >, Integer > counts = new HashMap<>(); - for ( Pair< File, Pair< Integer, Integer > > channelSrc : channelSources ) + for ( FileMapEntry channelSrc : channelSources ) { - Pair< File, Integer > key = new ValuePair< File, Integer >( channelSrc.getA(), channelSrc.getB().getA() ); + Pair< File, Integer > key = new ValuePair< File, Integer >( channelSrc.file(), channelSrc.series() ); if ( !counts.containsKey( key ) ) counts.put( key, 0 ); counts.put( key, counts.get( key ) + 1 ); @@ -119,12 +112,12 @@ public static Pair< Integer, Integer > getMinMaxNumSeriesIndexed(final FileListV if ( state.accumulativeMap.get( Tile.class ).size() < 1 ) return null; - final List< Pair< File, Pair< Integer, Integer > > > channelSources = state.accumulativeMap.get( Tile.class ) + final List< FileMapEntry > channelSources = state.accumulativeMap.get( Tile.class ) .values().iterator().next(); final Map< Pair< File, Integer >, Integer > counts = new HashMap<>(); - for ( Pair< File, Pair< Integer, Integer > > channelSrc : channelSources ) + for ( FileMapEntry channelSrc : channelSources ) { - Pair< File, Integer > key = new ValuePair< File, Integer >( channelSrc.getA(), channelSrc.getB().getB() ); + Pair< File, Integer > key = new ValuePair< File, Integer >( channelSrc.file(), channelSrc.channel() ); if ( !counts.containsKey( key ) ) counts.put( key, 0 ); counts.put( key, counts.get( key ) + 1 ); @@ -176,13 +169,13 @@ public Boolean getAmbiguousIllumChannel() { return ambiguousIllumChannel; } - - public Map > >> getAccumulateMap(Class cl) + + public Map< Object, List< FileMapEntry > > getAccumulateMap( Class< ? extends Entity > cl ) { return accumulativeMap.get( cl ); } - public Map< Pair< File, Pair< Integer, Integer > >, Pair< Dimensions, VoxelDimensions > > getDimensionMap() + public Map< FileMapEntry, Pair< Dimensions, VoxelDimensions > > getDimensionMap() { return dimensionMap; } @@ -197,7 +190,7 @@ public void setAmbiguousIllumChannel(Boolean ambiguousIllumChannel) this.ambiguousIllumChannel = ambiguousIllumChannel; } - public Map< Class< ? extends Entity >, Map< Integer, List< Pair< File, Pair< Integer, Integer > > > > > getIdMap() + public Map< Class< ? extends Entity >, Map< Integer, List< FileMapEntry > > > getIdMap() { return idMap; } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/FileMapImgLoaderLOCI.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/FileMapImgLoaderLOCI.java index 23ec3542..d7337203 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/FileMapImgLoaderLOCI.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/FileMapImgLoaderLOCI.java @@ -22,7 +22,6 @@ */ package net.preibisch.mvrecon.fiji.spimdata.imgloaders; -import java.io.File; import java.util.Map; import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; @@ -31,22 +30,22 @@ import net.imglib2.img.ImgFactory; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.integer.UnsignedShortType; -import net.imglib2.util.Pair; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapGettable; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; public class FileMapImgLoaderLOCI extends LegacyImgLoaderWrapper< UnsignedShortType, LegacyFileMapImgLoaderLOCI > implements FileMapGettable { public boolean zGrouped; public FileMapImgLoaderLOCI( - Map>> fileMap, - final AbstractSequenceDescription sequenceDescription) + Map< ? extends ViewId, FileMapEntry > fileMap, + final AbstractSequenceDescription< ?, ?, ? > sequenceDescription ) { this(fileMap, sequenceDescription, false); } public FileMapImgLoaderLOCI( - Map>> fileMap, + Map< ? extends ViewId, FileMapEntry > fileMap, final AbstractSequenceDescription sequenceDescription, final boolean zGrouped) { @@ -61,12 +60,12 @@ public FileMapImgLoaderLOCI( public String toString() { return legacyImgLoader.toString(); } - + @Override - public Map< ViewId, Pair< File, Pair< Integer, Integer > > > getFileMap() + public Map< ViewId, FileMapEntry > getFileMap() { return ( (LegacyFileMapImgLoaderLOCI) legacyImgLoader ).getFileMap(); } - + } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/LegacyFileMapImgLoaderLOCI.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/LegacyFileMapImgLoaderLOCI.java index 9c2bdfb1..066bb82b 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/LegacyFileMapImgLoaderLOCI.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/LegacyFileMapImgLoaderLOCI.java @@ -72,49 +72,49 @@ import net.preibisch.legacy.io.IOFunctions; import net.preibisch.mvrecon.fiji.spimdata.SpimData2; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapGettable; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.util.BioformatsReaderUtils; import util.ImgLib2Tools; public class LegacyFileMapImgLoaderLOCI extends AbstractImgFactoryImgLoader { - - private HashMap>> fileMap; + + private Map< ViewId, FileMapEntry > fileMap; private AbstractSequenceDescription< ?, ?, ? > sd; private boolean allTimepointsInSingleFiles; private boolean zGrouped; private File tempDir; public LegacyFileMapImgLoaderLOCI( - Map>> fileMap, + Map< ? extends ViewId, FileMapEntry > fileMap, final AbstractSequenceDescription sequenceDescription) { this(fileMap, sequenceDescription, false); } - + public LegacyFileMapImgLoaderLOCI( - Map>> fileMap, - final AbstractSequenceDescription sequenceDescription, - final boolean zGrouped) + Map< ? extends ViewId, FileMapEntry > fileMap, + final AbstractSequenceDescription< ?, ?, ? > sequenceDescription, + final boolean zGrouped ) { super(); this.tempDir = Files.createTempDir(); - this.fileMap = new HashMap<>(); - this.fileMap.putAll( fileMap ); + this.fileMap = new HashMap<>( fileMap ); this.sd = sequenceDescription; allTimepointsInSingleFiles = true; this.zGrouped = zGrouped; - + // populate map file -> {time points} Map< File, Set< Integer > > tpsPerFile = new HashMap<>(); for ( ViewId vId : fileMap.keySet() ) { - final File fileForVd = fileMap.get( vId ).getA(); + final File fileForVd = fileMap.get( vId ).file(); if ( !tpsPerFile.containsKey( fileForVd ) ) tpsPerFile.put( fileForVd, new HashSet<>() ); @@ -153,15 +153,15 @@ public RandomAccessibleInterval< UnsignedShortType > getImage(ViewId view) final RandomAccessibleInterval< UnsignedShortType > img = openImg( new UnsignedShortType(), view ); if ( img == null ) - throw new RuntimeException( "Could not load '" + fileMap.get( sd.getViewDescriptions( ).get( view ) ).getA() + "' viewId=" + view.getViewSetupId() + ", tpId=" + view.getTimePointId() ); + throw new RuntimeException( "Could not load '" + fileMap.get( sd.getViewDescriptions( ).get( view ) ).file() + "' viewId=" + view.getViewSetupId() + ", tpId=" + view.getTimePointId() ); + - return img; } catch ( Exception e ) { e.printStackTrace(); - throw new RuntimeException( "Could not load '" + fileMap.get( sd.getViewDescriptions( ).get( view ) ).getA() + "' viewId=" + view.getViewSetupId() + ", tpId=" + view.getTimePointId() + ": " + e ); + throw new RuntimeException( "Could not load '" + fileMap.get( sd.getViewDescriptions( ).get( view ) ).file() + "' viewId=" + view.getViewSetupId() + ", tpId=" + view.getTimePointId() + ": " + e ); } } @@ -187,7 +187,7 @@ protected < T extends RealType< T > & NativeType< T > > RandomAccessibleInterval // load dimensions loadMetaData( view ); - final File fileForVId = fileMap.get( view ).getA(); + final File fileForVId = fileMap.get( view ).file(); // use a new ImageReader since we might be loading multi-threaded and BioFormats is not thread-save // use Memoizer to cache ReaderState for each File on disk @@ -207,17 +207,17 @@ protected < T extends RealType< T > & NativeType< T > > RandomAccessibleInterval reader.setId( fileForVId.getAbsolutePath() ); if (zGrouped) ( (FileStitcher) ( (Memoizer) reader).getReader() ).setAxisTypes( new int[] {AxisGuesser.Z_AXIS} ); - reader.setSeries( fileMap.get( view ).getB().getA() ); + reader.setSeries( fileMap.get( view ).series() ); final BasicViewDescription< ? > vd = sd.getViewDescriptions().get( view ); - final BasicViewSetup vs = vd.getViewSetup(); - final File file = fileMap.get( vd).getA(); + final BasicViewSetup vs = vd.getViewSetup(); + final File file = fileMap.get( vd).file(); final TimePoint t = vd.getTimePoint(); final Angle a = getAngle( vd ); final Channel c = getChannel( vd ); final Illumination i = getIllumination( vd ); - final Tile tile = getTile( vd ); + final Tile tile = getTile( vd ); // we assume the size to have been set beforehand final int[] dim; @@ -252,8 +252,8 @@ protected < T extends RealType< T > & NativeType< T > > RandomAccessibleInterval " type=" + FormatTools.getPixelTypeString( reader.getPixelType()) + " img=" + img.getClass().getSimpleName() + "<" + type.getClass().getSimpleName() + ">]" ); - - int ch = fileMap.get( vd ).getB().getB(); + + int ch = fileMap.get( vd ).channel(); int tpNo = allTimepointsInSingleFiles ? 0 : t.getId(); System.out.println( "allTimepointsInSingleFiles " + allTimepointsInSingleFiles ); @@ -373,7 +373,7 @@ protected static Tile getTile( final BasicViewDescription< ? > vd ) } - public Map< ViewId, Pair< File, Pair< Integer, Integer > > > getFileMap() + public Map< ViewId, FileMapEntry > getFileMap() { return fileMap; } @@ -395,11 +395,11 @@ public static boolean isZSizeEqualInEveryFile(final SpimData2 spimData, final Fi if (!vd.isPresent()) return; - final File invKey = e.getValue().getA(); + final File invKey = e.getValue().file(); if (!invertedMap.containsKey( invKey )) invertedMap.put( invKey, new HashMap<>() ); - final Integer series = e.getValue().getB().getA(); + final Integer series = e.getValue().series(); invertedMap.get( invKey ).put( series, vd ); }); @@ -450,7 +450,7 @@ public static & NativeType< T >, IL extends ImgLoader & if (!vd.isPresent()) return; - final Pair< File, Integer > invKey = new ValuePair<>( e.getValue().getA(), e.getValue().getB().getA() ); + final Pair< File, Integer > invKey = new ValuePair<>( e.getValue().file(), e.getValue().series() ); if (!invertedMap.containsKey( invKey )) invertedMap.put( invKey, new ArrayList<>() ); diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/XmlIoFileListImgLoaderLOCI.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/XmlIoFileListImgLoaderLOCI.java index 8e2bfa8f..17c8457c 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/XmlIoFileListImgLoaderLOCI.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/XmlIoFileListImgLoaderLOCI.java @@ -22,7 +22,6 @@ */ package net.preibisch.mvrecon.fiji.spimdata.imgloaders; -import static mpicbg.spim.data.XmlHelpers.loadPath; import static mpicbg.spim.data.XmlKeys.IMGLOADER_FORMAT_ATTRIBUTE_NAME; import java.io.File; @@ -33,17 +32,10 @@ import mpicbg.spim.data.XmlHelpers; import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; -import mpicbg.spim.data.generic.sequence.BasicViewDescription; import mpicbg.spim.data.generic.sequence.ImgLoaderIo; import mpicbg.spim.data.generic.sequence.XmlIoBasicImgLoader; import mpicbg.spim.data.sequence.ViewId; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.img.cell.CellImgFactory; -import net.imglib2.img.planar.PlanarImgFactory; -import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Pair; -import net.imglib2.util.ValuePair; +import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapEntry; @ImgLoaderIo( format = "spimreconstruction.filelist", type = FileMapImgLoaderLOCI.class ) public class XmlIoFileListImgLoaderLOCI implements XmlIoBasicImgLoader< FileMapImgLoaderLOCI > @@ -58,36 +50,31 @@ public class XmlIoFileListImgLoaderLOCI implements XmlIoBasicImgLoader< FileMapI public static final String MAPPING_FILE_TAG = "file"; public static final String MAPPING_SERIES_TAG = "series"; public static final String MAPPING_C_TAG = "channel"; - + @Override public Element toXml(FileMapImgLoaderLOCI imgLoader, File basePath) { - Map< ViewId, Pair< File, Pair< Integer, Integer > > > fileMap = imgLoader.getFileMap(); - final Element wholeElem = new Element( "ImageLoader" ); wholeElem.setAttribute( IMGLOADER_FORMAT_ATTRIBUTE_NAME, this.getClass().getAnnotation( ImgLoaderIo.class ).format() ); wholeElem.addContent( XmlHelpers.booleanElement( ZGROUPED_TAG, imgLoader.zGrouped ) ); final Element filesElement = new Element( FILES_TAG ); - - for (ViewId vid : fileMap.keySet()) - { - final Pair< File, Pair< Integer, Integer > > pair = fileMap.get( vid ); + final Map< ViewId, FileMapEntry > fileMap = imgLoader.getFileMap(); + fileMap.forEach( ( vid, entry ) -> { final Element fileMappingElement = new Element( FILE_MAPPING_TAG ); - fileMappingElement.setAttribute( MAPPING_VS_TAG, Integer.toString( vid.getViewSetupId()) ); - fileMappingElement.setAttribute( MAPPING_TP_TAG, Integer.toString( vid.getTimePointId()) ); - fileMappingElement.addContent( XmlHelpers.pathElement( MAPPING_FILE_TAG, pair.getA(), basePath ) ); - fileMappingElement.setAttribute( MAPPING_SERIES_TAG, Integer.toString(pair.getB().getA()) ); - fileMappingElement.setAttribute( MAPPING_C_TAG, Integer.toString(pair.getB().getB()) ); - + fileMappingElement.setAttribute( MAPPING_VS_TAG, Integer.toString( vid.getViewSetupId() ) ); + fileMappingElement.setAttribute( MAPPING_TP_TAG, Integer.toString( vid.getTimePointId() ) ); + fileMappingElement.addContent( XmlHelpers.pathElement( MAPPING_FILE_TAG, entry.file(), basePath ) ); + fileMappingElement.setAttribute( MAPPING_SERIES_TAG, Integer.toString( entry.series() ) ); + fileMappingElement.setAttribute( MAPPING_C_TAG, Integer.toString( entry.channel() ) ); filesElement.addContent( fileMappingElement ); - } - + } ); + //elem.addContent( XmlHelpers.pathElement( DIRECTORY_TAG, imgLoader.getCZIFile().getParentFile(), basePath ) ); //wholeElem.addContent( XmlHelpers.textElement( MASTER_FILE_TAG, imgLoader.getCZIFile().getName() ) ); - + wholeElem.addContent( filesElement ); - + return wholeElem; } @@ -98,22 +85,19 @@ public FileMapImgLoaderLOCI fromXml(Element elem, File basePath, //final File path = loadPath( elem, DIRECTORY_TAG, basePath ); final Element fileMapElement = elem.getChild( FILES_TAG ); final boolean zGrouped = XmlHelpers.getBoolean( elem, ZGROUPED_TAG, false ); - - final HashMap< BasicViewDescription< ? >, Pair< File, Pair< Integer, Integer > > > fileMap = new HashMap<>(); - + + final Map< ViewId, FileMapEntry > fileMap = new HashMap<>(); + for (Element e : fileMapElement.getChildren( FILE_MAPPING_TAG )){ int vs = Integer.parseInt( e.getAttribute( MAPPING_VS_TAG ).getValue()); int tp = Integer.parseInt( e.getAttribute( MAPPING_TP_TAG ).getValue()); int series = Integer.parseInt( e.getAttribute( MAPPING_SERIES_TAG ).getValue()); int channel = Integer.parseInt( e.getAttribute( MAPPING_C_TAG ).getValue()); File f = XmlHelpers.loadPath( e, MAPPING_FILE_TAG, basePath ); - - BasicViewDescription< ? > vd = sequenceDescription.getViewDescriptions().get( new ViewId( tp, vs ) ); - Pair< File, Pair< Integer, Integer > > p = new ValuePair< File, Pair >( f, new ValuePair< Integer, Integer >( series, channel ) ); - - fileMap.put( vd, p ); + + fileMap.put( new ViewId( tp, vs ), new FileMapEntry( f, series, channel ) ); } - + return new FileMapImgLoaderLOCI( fileMap, sequenceDescription, zGrouped ); } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapEntry.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapEntry.java new file mode 100644 index 00000000..1f3ee78d --- /dev/null +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapEntry.java @@ -0,0 +1,53 @@ +package net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2; + +import java.io.File; +import java.util.Objects; + +public class FileMapEntry +{ + private final File file; + + private final int series; + + private final int channel; + + // TODO: rename to FileSeriesChannel ? + public FileMapEntry( final File file, final int series, final int channel ) + { + this.file = file; + this.series = series; + this.channel = channel; + } + + public File file() + { + return file; + } + + public int series() + { + return series; + } + + public int channel() + { + return channel; + } + + @Override + public boolean equals( final Object o ) + { + if ( this == o ) + return true; + if ( !( o instanceof FileMapEntry ) ) + return false; + final FileMapEntry that = ( FileMapEntry ) o; + return series == that.series && channel == that.channel && Objects.equals( file, that.file ); + } + + @Override + public int hashCode() + { + return Objects.hash( file, series, channel ); + } +} diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapGettable.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapGettable.java index cfc6a31e..8f24c04b 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapGettable.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapGettable.java @@ -22,13 +22,11 @@ */ package net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2; -import java.io.File; import java.util.Map; import mpicbg.spim.data.sequence.ViewId; -import net.imglib2.util.Pair; public interface FileMapGettable { - public Map< ? extends ViewId, Pair< File, Pair< Integer, Integer > > > getFileMap(); + Map< ? extends ViewId, FileMapEntry > getFileMap(); } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapImgLoaderLOCI2.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapImgLoaderLOCI2.java index 23d6c57c..1f2cad49 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapImgLoaderLOCI2.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/FileMapImgLoaderLOCI2.java @@ -9,12 +9,12 @@ * 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 * . @@ -27,197 +27,174 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import com.google.common.io.Files; import loci.formats.FileStitcher; -import loci.formats.FormatTools; import loci.formats.IFormatReader; import loci.formats.Memoizer; 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.generic.sequence.ImgLoaderHint; -import mpicbg.spim.data.generic.sequence.ImgLoaderHints; import mpicbg.spim.data.sequence.ImgLoader; import mpicbg.spim.data.sequence.SetupImgLoader; import mpicbg.spim.data.sequence.ViewId; import mpicbg.spim.data.sequence.VoxelDimensions; -import net.imglib2.Cursor; import net.imglib2.Dimensions; -import net.imglib2.RandomAccess; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.exception.IncompatibleTypeException; -import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.img.cell.CellImgFactory; +import net.imglib2.cache.Cache; +import net.imglib2.cache.ref.WeakRefLoaderCache; +import net.imglib2.converter.RealTypeConverters; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.ShortType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.type.numeric.integer.UnsignedIntType; -import net.imglib2.type.numeric.integer.UnsignedShortType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.util.Pair; -import net.imglib2.view.Views; +import net.imglib2.util.CloseableThreadLocal; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.util.BioformatsReaderUtils; import util.ImgLib2Tools; public class FileMapImgLoaderLOCI2 implements ImgLoader, FileMapGettable { - private final HashMap>> fileMap; - private final AbstractSequenceDescription sd; - private boolean allTimepointsInSingleFiles; + private final Map< ViewId, FileMapEntry > fileMap; + private final File tempDir; - public boolean zGrouped; + + private final AbstractSequenceDescription< ?, ?, ? > sd; + + final boolean zGrouped; + + private final boolean allTimepointsInSingleFiles; + + private final Map< Integer, SetupImgLoader< ? > > setupImgLoaders = new ConcurrentHashMap<>(); public FileMapImgLoaderLOCI2( - final Map>> fileMap, - final AbstractSequenceDescription sequenceDescription) + final Map< ? extends ViewId, FileMapEntry > fileMap, + final AbstractSequenceDescription< ?, ?, ? > sequenceDescription ) { - this(fileMap, sequenceDescription, false); + this( fileMap, sequenceDescription, false ); } - - public FileMapImgLoaderLOCI2(Map>> fileMap, - final AbstractSequenceDescription sequenceDescription, - final boolean zGrouped) - { - this.fileMap = new HashMap<>(); - this.fileMap.putAll( fileMap ); + public FileMapImgLoaderLOCI2( Map< ? extends ViewId, FileMapEntry > fileMap, + final AbstractSequenceDescription< ?, ?, ? > sequenceDescription, + final boolean zGrouped ) + { + this.fileMap = new HashMap<>( fileMap ); this.tempDir = Files.createTempDir(); - this.sd = sequenceDescription; this.zGrouped = zGrouped; - allTimepointsInSingleFiles = true; - // populate map file -> {time points} - Map< File, Set< Integer > > tpsPerFile = new HashMap<>(); - for ( ViewId vid : fileMap.keySet() ) + final Map< File, Set< Integer > > tpsPerFile = new HashMap<>(); + boolean allTimepointsInSingleFiles = true; + for ( final Map.Entry< ? extends ViewId, FileMapEntry > entry : fileMap.entrySet() ) { - - final File fileForVd = fileMap.get( vid ).getA(); - if ( !tpsPerFile.containsKey( fileForVd ) ) - tpsPerFile.put( fileForVd, new HashSet<>() ); - - tpsPerFile.get( fileForVd ).add( vid.getTimePointId() ); + final ViewId vid = entry.getKey(); + final File file = entry.getValue().file(); + final Set< Integer > tps = tpsPerFile.computeIfAbsent( file, k -> new HashSet<>() ); + tps.add( vid.getTimePointId() ); // the current file has more than one time point - if ( tpsPerFile.get( fileForVd ).size() > 1 ) + if ( tps.size() > 1 ) { allTimepointsInSingleFiles = false; break; } - } + this.allTimepointsInSingleFiles = allTimepointsInSingleFiles; + + this.getReader = () -> { + // use a new ImageReader since we might be loading multi-threaded and BioFormats is not thread-save + // use Memoizer to cache ReaderState for each File on disk + // see: https://www-legacy.openmicroscopy.org/site/support/bio-formats5.1/developers/matlab-dev.html#reader-performance + IFormatReader reader = null; + if ( zGrouped ) + { + final FileStitcher fs = new FileStitcher( true ); + fs.setCanChangePattern( false ); + reader = new Memoizer( fs, Memoizer.DEFAULT_MINIMUM_ELAPSED, tempDir ); + } + else + { + reader = new Memoizer( BioformatsReaderUtils.createImageReaderWithSetupHooks(), Memoizer.DEFAULT_MINIMUM_ELAPSED, tempDir ); + } - System.out.println( allTimepointsInSingleFiles ); + return reader; + }; } - @Override - public SetupImgLoader< ? > getSetupImgLoader(int setupId) + public SetupImgLoader< ? > getSetupImgLoader( int setupId ) { - return new FileMapSetupImgLoaderLOCI2<>(setupId); + return setupImgLoaders.computeIfAbsent( setupId, FileMapSetupImgLoaderLOCI2::new ); } - - - /* (non-Javadoc) - * @see spim.fiji.spimdata.imgloaders.filemap2.FileMapGettable#getFileMap() - */ + @Override - public Map< ViewId, Pair< File, Pair< Integer, Integer > > > getFileMap() + public Map< ViewId, FileMapEntry > getFileMap() { - return fileMap; + return fileMap; } - - public class FileMapSetupImgLoaderLOCI2 & NativeType< T >> implements SetupImgLoader< T > + + private final Supplier< IFormatReader > getReader; + + public class FileMapSetupImgLoaderLOCI2< T extends RealType< T > & NativeType< T > > implements SetupImgLoader< T > { - private int setupId; + private final int setupId; + + private final CloseableThreadLocal< IFormatReader > threadLocalReader = CloseableThreadLocal.withInitial( getReader ); + + private final Cache< Integer, RandomAccessibleInterval< T > > images = new WeakRefLoaderCache< Integer, RandomAccessibleInterval< T > >().withLoader( this::createImage ); + + private final Supplier< T > type; - public FileMapSetupImgLoaderLOCI2(int setupId) + public FileMapSetupImgLoaderLOCI2( int setupId ) { this.setupId = setupId; + this.type = lazyInit( () -> { + final BasicViewDescription< ? > aVd = getAnyPresentViewDescriptionForViewSetup( sd, setupId ); + if ( aVd == null ) + return null; + final FileMapEntry entry = fileMap.get( aVd ); + return VirtualRAIFactoryLOCI.getType( threadLocalReader::get, entry.file(), entry.series() ); + } ); } - private IFormatReader getReader() + private RandomAccessibleInterval< T > createImage( final int timepointId ) { - // use a new ImageReader since we might be loading multi-threaded and BioFormats is not thread-save - // use Memoizer to cache ReaderState for each File on disk - // see: https://www-legacy.openmicroscopy.org/site/support/bio-formats5.1/developers/matlab-dev.html#reader-performance - IFormatReader reader = null; - if (zGrouped) - { - final FileStitcher fs = new FileStitcher(true); - fs.setCanChangePattern( false ); - reader = new Memoizer( fs , Memoizer.DEFAULT_MINIMUM_ELAPSED, tempDir); - } - else - { - reader = new Memoizer( BioformatsReaderUtils.createImageReaderWithSetupHooks(), Memoizer.DEFAULT_MINIMUM_ELAPSED, tempDir ); - } - - return reader; + final FileMapEntry entry = fileMap.get( new ViewId( timepointId, setupId ) ); + return VirtualRAIFactoryLOCI.createVirtualCached( + threadLocalReader::get, + entry.file(), + entry.series(), + entry.channel(), + allTimepointsInSingleFiles ? 0 : timepointId ); } @Override - public RandomAccessibleInterval< T > getImage( final int timepointId, final ImgLoaderHint... hints) + public RandomAccessibleInterval< T > getImage( final int timepointId, final ImgLoaderHint... hints ) { - final BasicViewDescription< ? > vd = sd.getViewDescriptions().get( new ViewId( timepointId, setupId ) ); - final Pair< File, Pair< Integer, Integer > > imageSource = fileMap.get( vd ); - - // TODO: some logging here? (reading angle .. , tp .., ... from file ...) - - final Dimensions size = vd.getViewSetup().getSize(); - - final IFormatReader reader = getReader(); - - RandomAccessibleInterval< T > img = null; try { - img = (RandomAccessibleInterval< T >) (Object)new VirtualRAIFactoryLOCI().createVirtualCached( - reader, imageSource.getA(), imageSource.getB().getA(), - imageSource.getB().getB(), allTimepointsInSingleFiles ? 0 : timepointId, new UnsignedShortType(), size ); + return images.get( timepointId ); } - catch ( IncompatibleTypeException e ) + catch ( ExecutionException e ) { - e.printStackTrace(); + throw new RuntimeException( e ); } - - return img; } @Override public T getImageType() { - return (T) new UnsignedShortType(); - - /* - final BasicViewDescription< ? > aVd = getAnyPresentViewDescriptionForViewSetup( sd, setupId ); - final Pair< File, Pair< Integer, Integer > > aPair = fileMap.get( aVd ); - - final IFormatReader reader = getReader(); - VirtualRAIFactoryLOCI.setReaderFileAndSeriesIfNecessary( reader, aPair.getA(), aPair.getB().getA() ); - - if (reader.getPixelType() == FormatTools.UINT8) - return (T) new UnsignedByteType(); - else if (reader.getPixelType() == FormatTools.UINT16) - return (T) new UnsignedShortType(); - else if (reader.getPixelType() == FormatTools.INT16) - return (T) new ShortType(); - else if (reader.getPixelType() == FormatTools.UINT32) - return (T) new UnsignedIntType(); - else if (reader.getPixelType() == FormatTools.FLOAT) - return (T) new FloatType(); - return null; - */ + return type.get(); } @Override - public RandomAccessibleInterval< FloatType > getFloatImage(int timepointId, boolean normalize, - ImgLoaderHint... hints) + public RandomAccessibleInterval< FloatType > getFloatImage( int timepointId, boolean normalize, + ImgLoaderHint... hints ) { if ( normalize ) return ImgLib2Tools.normalizeVirtualRAI( getImage( timepointId, hints ) ); @@ -226,52 +203,69 @@ public RandomAccessibleInterval< FloatType > getFloatImage(int timepointId, bool } @Override - public Dimensions getImageSize(int timepointId) + public Dimensions getImageSize( int timepointId ) { // NB: in all current uses we should have size information in the sd - BasicViewDescription< ? > vd = sd.getViewDescriptions().get( new ViewId( timepointId, setupId ) ); - return vd.getViewSetup().getSize(); + return getViewSetup( timepointId ).getSize(); } @Override - public VoxelDimensions getVoxelSize(int timepointId) + public VoxelDimensions getVoxelSize( int timepointId ) { // NB: in all current uses we should have size information in the sd - BasicViewDescription< ? > vd = sd.getViewDescriptions().get( new ViewId( timepointId, setupId ) ); - return vd.getViewSetup().getVoxelSize(); + return getViewSetup( timepointId ).getVoxelSize(); } - } - - /** - * copy src to dest - * @param src : source, will not be modified - * @param dest : destiantion, will be modified - * @param pixel type source - * @param pixel type destination - */ - public static , S extends RealType> void copy(RandomAccessible< T > src, RandomAccessibleInterval< S > dest) - { - final Cursor< S > destCursor = Views.iterable( dest ).localizingCursor(); - final RandomAccess< T > srcRA = src.randomAccess(); - - while (destCursor.hasNext()) + private BasicViewSetup getViewSetup( int timepointId ) { - destCursor.fwd(); - srcRA.setPosition( destCursor ); - destCursor.get().setReal( srcRA.get().getRealDouble() ); + BasicViewDescription< ? > vd = sd.getViewDescriptions().get( new ViewId( timepointId, setupId ) ); + return vd.getViewSetup(); } - } - public static BasicViewDescription< ? > getAnyPresentViewDescriptionForViewSetup(AbstractSequenceDescription< ?, ?, ? > sd, int viewSetupId) + private static BasicViewDescription< ? > getAnyPresentViewDescriptionForViewSetup( AbstractSequenceDescription< ?, ?, ? > sd, int viewSetupId ) { - for (final ViewId vid : sd.getViewDescriptions().keySet()) - if (vid.getViewSetupId() == viewSetupId) - if (!sd.getMissingViews().getMissingViews().contains( vid )) + for ( final ViewId vid : sd.getViewDescriptions().keySet() ) + if ( vid.getViewSetupId() == viewSetupId ) + if ( !sd.getMissingViews().getMissingViews().contains( vid ) ) return sd.getViewDescriptions().get( vid ); return null; } + private static < T > Supplier< T > lazyInit( final Supplier< T > supplier ) + { + return new Supplier< T >() + { + T value = null; + + @Override + public synchronized T get() + { + if ( value == null ) + value = supplier.get(); + return value; + } + }; + } + + /** + * copy src to dest + * + * @deprecated Use {@link RealTypeConverters#copyFromTo(RandomAccessible, RandomAccessibleInterval)}. + * + * @param src + * source, will not be modified + * @param dest + * destiantion, will be modified + * @param + * pixel type source + * @param + * pixel type destination + */ + @Deprecated + public static < T extends RealType< T >, S extends RealType< S > > void copy( RandomAccessible< T > src, RandomAccessibleInterval< S > dest ) + { + RealTypeConverters.copyFromTo( src, dest ); + } } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRAIFactoryLOCI.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRAIFactoryLOCI.java index f92dcf33..fb4a8d56 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRAIFactoryLOCI.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRAIFactoryLOCI.java @@ -9,12 +9,12 @@ * 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 * . @@ -22,142 +22,192 @@ */ package net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2; +import static java.nio.ByteOrder.BIG_ENDIAN; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static net.imglib2.cache.img.ReadOnlyCachedCellImgOptions.options; + import java.io.File; import java.io.IOException; -import java.util.Objects; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.function.Supplier; import loci.formats.AxisGuesser; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.formats.IFormatReader; -import loci.formats.ImageReader; import loci.formats.Memoizer; -import net.imglib2.Dimensions; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.cache.img.ReadOnlyCachedCellImgFactory; import net.imglib2.exception.IncompatibleTypeException; -import net.imglib2.img.Img; -import net.imglib2.img.cell.CellImgFactory; -import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.type.NativeType; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.integer.ShortType; import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.type.numeric.integer.UnsignedIntType; import net.imglib2.type.numeric.integer.UnsignedShortType; -import net.imglib2.type.numeric.real.DoubleType; import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.view.Views; -import net.preibisch.mvrecon.fiji.spimdata.imgloaders.LegacyStackImgLoaderLOCI; -import net.preibisch.mvrecon.process.fusion.FusionTools; +import net.imglib2.util.Cast; -public class VirtualRAIFactoryLOCI +class VirtualRAIFactoryLOCI { - @FunctionalInterface - interface TriConsumer + static < T extends RealType< T > & NativeType< T > > T getType( + final Supplier< IFormatReader > threadLocalReader, + final File file, + final int series ) { - void accept(A a, B b, C c); - - default TriConsumer< A, B, C > andThen(TriConsumer< ? super A, ? super B, ? super C > after) + try { - Objects.requireNonNull( after ); + final IFormatReader reader = threadLocalReader.get(); + setReaderFileAndSeriesIfNecessary( reader, file, series ); - return (a, b, c) -> { - accept( a, b, c ); - after.accept( a, b, c ); - }; + final int pixelType = reader.getPixelType(); + switch ( pixelType ) + { + case FormatTools.UINT8: + return Cast.unchecked( new UnsignedByteType() ); + case FormatTools.UINT16: + return Cast.unchecked( new UnsignedShortType() ); + case FormatTools.INT16: + return Cast.unchecked( new ShortType() ); + case FormatTools.UINT32: + return Cast.unchecked( new UnsignedIntType() ); + case FormatTools.FLOAT: + return Cast.unchecked( new FloatType() ); + default: + return null; + } + } + catch ( IOException | FormatException e ) + { + throw new RuntimeException( e ); } } - - @SuppressWarnings("unchecked") - public & NativeType< T >> RandomAccessibleInterval< T > createVirtual( - final IFormatReader reader, + + static < T extends RealType< T > & NativeType< T > > RandomAccessibleInterval< T > createVirtualCached( + final Supplier threadLocalReader, final File file, final int series, final int channel, - final int timepoint, - T type, - Dimensions dim) throws IncompatibleTypeException + final int timepoint ) throws IncompatibleTypeException { - setReaderFileAndSeriesIfNecessary( reader, file, series ); + final IFormatReader reader = threadLocalReader.get(); + try + { + setReaderFileAndSeriesIfNecessary( reader, file, series ); + } + catch ( IOException | FormatException e ) + { + throw new RuntimeException( e ); + } - final boolean isLittleEndian = reader.isLittleEndian(); - final long[] dims = new long[]{reader.getSizeX(), reader.getSizeY(), reader.getSizeZ()}; + final long[] dims = { reader.getSizeX(), reader.getSizeY(), reader.getSizeZ() }; + final int[] cellDims = { ( int ) dims[ 0 ], ( int ) dims[ 1 ], 1 }; + final ReadOnlyCachedCellImgFactory factory = new ReadOnlyCachedCellImgFactory( options().cellDimensions( cellDims ) ); - if (dim != null) - dim.dimensions( dims ); + final ByteOrder byteOrder = reader.isLittleEndian() ? LITTLE_ENDIAN : BIG_ENDIAN; final int pixelType = reader.getPixelType(); - if (pixelType == FormatTools.UINT8) - return new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedByteType() : type, (t, buf, i) -> {t.setReal( (int) buf[i] & 0xff);} ); - else if (pixelType == FormatTools.UINT16) - return new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedShortType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getShortValueInt( buf, i*2, isLittleEndian ) );} ); - else if (pixelType == FormatTools.INT16) - return new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new ShortType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getShortValue( buf, i*2, isLittleEndian ) );} ); - else if (pixelType == FormatTools.UINT32) - return new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedIntType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getIntValue( buf, i*4, isLittleEndian ) );} ); - else if (pixelType == FormatTools.FLOAT) - return new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new FloatType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getFloatValue( buf, i*4, isLittleEndian ) );} ); - else - throw new IncompatibleTypeException( this, "cannot create virtual image for this pixel type" ); + switch ( pixelType ) + { + case FormatTools.UINT8: + return Cast.unchecked( factory.create( dims, new UnsignedByteType(), + cell -> { + final int z = ( int ) cell.min( 2 ); + final ByteBuffer bytes = readIntoBuffer( threadLocalReader.get(), file, series, channel, timepoint, z ); + bytes.position( 0 ); + bytes.get( ( byte[] ) cell.getStorageArray() ); + } ) ); + case FormatTools.UINT16: + return Cast.unchecked( factory.create( dims, new UnsignedShortType(), + cell -> { + final int z = ( int ) cell.min( 2 ); + final ByteBuffer bytes = readIntoBuffer( threadLocalReader.get(), file, series, channel, timepoint, z ); + final ShortBuffer shorts = bytes.order( byteOrder ).asShortBuffer(); + shorts.position( 0 ); + shorts.get( ( short[] ) cell.getStorageArray() ); + } ) ); + case FormatTools.INT16: + return Cast.unchecked( factory.create( dims, new ShortType(), + cell -> { + final int z = ( int ) cell.min( 2 ); + final ByteBuffer bytes = readIntoBuffer( threadLocalReader.get(), file, series, channel, timepoint, z ); + final ShortBuffer shorts = bytes.order( byteOrder ).asShortBuffer(); + shorts.position( 0 ); + shorts.get( ( short[] ) cell.getStorageArray() ); + } ) ); + case FormatTools.UINT32: + return Cast.unchecked( factory.create( dims, new UnsignedIntType(), + cell -> { + final int z = ( int ) cell.min( 2 ); + final ByteBuffer bytes = readIntoBuffer( threadLocalReader.get(), file, series, channel, timepoint, z ); + final IntBuffer ints = bytes.order( byteOrder ).asIntBuffer(); + ints.position( 0 ); + ints.get( ( int[] ) cell.getStorageArray() ); + } ) ); + case FormatTools.FLOAT: + return Cast.unchecked( factory.create( dims, new FloatType(), + cell -> { + final int z = ( int ) cell.min( 2 ); + final ByteBuffer bytes = readIntoBuffer( threadLocalReader.get(), file, series, channel, timepoint, z ); + final FloatBuffer floats = bytes.order( byteOrder ).asFloatBuffer(); + floats.position( 0 ); + floats.get( ( float[] ) cell.getStorageArray() ); + } ) ); + default: + throw new IncompatibleTypeException( new VirtualRAIFactoryLOCI(), "cannot create virtual image for this pixel type: " + pixelType ); + } } - - @SuppressWarnings("unchecked") - public synchronized & NativeType< T >> RandomAccessibleInterval< T > createVirtualCached( + + private static ByteBuffer readIntoBuffer( final IFormatReader reader, final File file, final int series, final int channel, final int timepoint, - T type, - Dimensions dim) throws IncompatibleTypeException + final int z ) throws IOException, FormatException { setReaderFileAndSeriesIfNecessary( reader, file, series ); +// System.out.println( "reading z plane " + z + " from series " + series + " in file " + file.getAbsolutePath() ); - final boolean isLittleEndian = reader.isLittleEndian(); - final long[] dims = new long[]{reader.getSizeX(), reader.getSizeY(), reader.getSizeZ()}; + final int planeSize = ( reader.getBitsPerPixel() / 8 ) * reader.getSizeX() * reader.getSizeY(); + final int size = planeSize * reader.getRGBChannelCount(); + final byte[] buffer = new byte[ size ]; - if (dim != null) - dim.dimensions( dims ); + // FIX for XYZ <-> XYT mixup in rare cases + final boolean flipTAndZ = !reader.isOrderCertain() && reader.getSizeZ() <= 1 && reader.getSizeT() > 1; + final int actualTP = flipTAndZ ? z : timepoint; + final int actualZ = flipTAndZ ? timepoint : z; - final int pixelType = reader.getPixelType(); - - if (pixelType == FormatTools.UINT8) - { - RandomAccessibleInterval< T > virtualImg = new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedByteType() : type, (t, buf, i) -> {t.setReal( (int) buf[i] & 0xff);} ); - return FusionTools.cacheRandomAccessibleInterval( virtualImg, Integer.MAX_VALUE, type == null ? (T) new UnsignedByteType() : type, new int[] {(int)virtualImg.dimension( 0 ), (int)virtualImg.dimension( 1 ), 1} ) ; - } - else if (pixelType == FormatTools.UINT16) - { - RandomAccessibleInterval< T > virtualImg = new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedShortType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getShortValueInt( buf, i*2, isLittleEndian ) );} ); - return FusionTools.cacheRandomAccessibleInterval( virtualImg, Integer.MAX_VALUE, type == null ? (T) new UnsignedShortType() : type, new int[] {(int)virtualImg.dimension( 0 ), (int)virtualImg.dimension( 1 ), 1} ) ; - } - else if (pixelType == FormatTools.INT16) + final int rgbOffset; + if ( reader.getRGBChannelCount() == reader.getSizeC() ) { - RandomAccessibleInterval< T > virtualImg = new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new ShortType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getShortValue( buf, i*2, isLittleEndian ) );} ); - return FusionTools.cacheRandomAccessibleInterval( virtualImg, Integer.MAX_VALUE, type == null ? (T) new ShortType() : type, new int[] {(int)virtualImg.dimension( 0 ), (int)virtualImg.dimension( 1 ), 1} ) ; + // the image is RGB -> we have to read bytes for all channels at once? + reader.openBytes( reader.getIndex( actualZ, 0, actualTP ), buffer ); + rgbOffset = channel * planeSize; } - else if (pixelType == FormatTools.UINT32) - { - RandomAccessibleInterval< T > virtualImg = new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new UnsignedIntType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getIntValue( buf, i*4, isLittleEndian ) );} ); - return FusionTools.cacheRandomAccessibleInterval( virtualImg, Integer.MAX_VALUE, type == null ? (T) new UnsignedIntType() : type, new int[] {(int)virtualImg.dimension( 0 ), (int)virtualImg.dimension( 1 ), 1} ) ; - } - else if (pixelType == FormatTools.FLOAT) + else { - RandomAccessibleInterval< T > virtualImg = new VirtualRandomAccessibleIntervalLOCI< T >( reader, file, dims, series, channel, timepoint, type == null ? (T) new FloatType() : type, (t, buf, i) -> {t.setReal( LegacyStackImgLoaderLOCI.getFloatValue( buf, i*4, isLittleEndian ) );} ); - return FusionTools.cacheRandomAccessibleInterval( virtualImg, Integer.MAX_VALUE, type == null ? (T) new FloatType() : type, new int[] {(int)virtualImg.dimension( 0 ), (int)virtualImg.dimension( 1 ), 1} ) ; + // normal image -> read specified channel + reader.openBytes( reader.getIndex( actualZ, channel, actualTP ), buffer ); + rgbOffset = 0; } - else - throw new IncompatibleTypeException( this, "cannot create virtual image for this pixel type: " + pixelType ); + + return ByteBuffer.wrap( buffer, rgbOffset, planeSize ); } - + /** * ensure that the reader we have is set to the correct file and series * @param reader the reader * @param file the file to point the reader to * @param series the series in the file to point the reader to */ - public static void setReaderFileAndSeriesIfNecessary(final IFormatReader reader, final File file, final int series) + private static void setReaderFileAndSeriesIfNecessary(final IFormatReader reader, final File file, final int series) + throws IOException, FormatException { final boolean isFileStitcher = FileStitcher.class.isInstance( ( (Memoizer) reader).getReader() ); @@ -169,81 +219,28 @@ public static void setReaderFileAndSeriesIfNecessary(final IFormatReader reader, // FIXME: this would probably crash anyway (also for normal readers) as we setId while reader is not closed // but the way we call it, we never have to re-setID for the reader // TODO: investigate - if (!isFileStitcher) + if ( !isFileStitcher ) { // is the reader set to the right file? // we check the canonical path of the file, otherwise something /./ would lead to setId being called // again even though the correct file is set already - if (!haveToReadFile) - try { haveToReadFile |= !(new File(reader.getCurrentFile()).getCanonicalPath().equals( file.getCanonicalPath() ) ); } - catch (IOException e) { return; } + if ( !haveToReadFile ) + haveToReadFile = !( new File( reader.getCurrentFile() ).getCanonicalPath().equals( file.getCanonicalPath() ) ); } - if (haveToReadFile) + if ( haveToReadFile ) { - try - { - reader.setId( file.getAbsolutePath() ); + reader.close( ); + reader.setId( file.getAbsolutePath() ); - if ( isFileStitcher ) - ( (FileStitcher) ( (Memoizer) reader).getReader() ).setAxisTypes( new int[] {AxisGuesser.Z_AXIS} ); - } - catch ( FormatException | IOException e ) - { - e.printStackTrace(); - return; - } + if ( isFileStitcher ) + ( ( FileStitcher ) ( ( Memoizer ) reader ).getReader() ).setAxisTypes( new int[] { AxisGuesser.Z_AXIS } ); reader.setSeries( series ); } else { - if (reader.getSeries() != series) + if ( reader.getSeries() != series ) reader.setSeries( series ); } } - - /** check if the given reader is set to the given file and series - * - * @param reader the reader - * @param file the file - * @param series the series - * @return true or false - */ - public static boolean checkReaderFileAndSeries(final IFormatReader reader, final File file, final int series) - { - // if we have a fileStitcher, do not check the actual file name - final boolean isFileStitcher = FileStitcher.class.isInstance( ( (Memoizer) reader).getReader() ); - if (isFileStitcher) - if (reader.getCurrentFile() == null) - return false; - else - return reader.getSeries() == series; - - if (reader.getCurrentFile() == null || !reader.getCurrentFile().equals( file.getAbsolutePath() )) - return false; - else - return reader.getSeries() == series; - } - - public static & NativeType< T > > void main(String[] args) - { - RandomAccessibleInterval< T > img = null; - ImageReader reader = new ImageReader(); - try - { - img = new VirtualRAIFactoryLOCI().createVirtualCached( reader, new File( "/Users/david/Desktop/2ch2ill2angle.czi" ), 0, 2, 0 , (T) new DoubleType(), null); - } - catch ( IncompatibleTypeException e ) - { - e.printStackTrace(); - } - - Img< T > create = new CellImgFactory().create( img, Views.iterable( img ).firstElement().createVariable() ); - - - - System.out.println( Views.iterable( img ).firstElement().getClass()); - ImageJFunctions.show( img, "BDV" ); - System.out.println( reader.getModuloC().step ); - } } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRandomAccessibleIntervalLOCI.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRandomAccessibleIntervalLOCI.java deleted file mode 100644 index b58463b4..00000000 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/VirtualRandomAccessibleIntervalLOCI.java +++ /dev/null @@ -1,158 +0,0 @@ -/*- - * #%L - * Software for the reconstruction of multi-view microscopic acquisitions - * like Selective Plane Illumination Microscopy (SPIM) Data. - * %% - * Copyright (C) 2012 - 2024 Multiview Reconstruction 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 - * . - * #L% - */ -package net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2; - -import java.io.File; -import java.io.IOException; - -import loci.formats.FormatException; -import loci.formats.IFormatReader; -import net.imglib2.AbstractInterval; -import net.imglib2.Interval; -import net.imglib2.Point; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.Sampler; -import net.imglib2.type.NativeType; -import net.imglib2.type.numeric.RealType; -import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.VirtualRAIFactoryLOCI.TriConsumer; - -class VirtualRandomAccessibleIntervalLOCI & NativeType< T >> extends AbstractInterval - implements RandomAccessibleInterval< T > -{ - private final IFormatReader reader; - private final File file; - private final int series; - private final int channel; - private final int timepoint; - private final T type; - private final TriConsumer< T, byte[], Integer > byteConverter; - - VirtualRandomAccessibleIntervalLOCI(IFormatReader reader, File file, long[] dims, int series, int channel, - int timepoint, T type, final TriConsumer< T, byte[], Integer > byteConverter) - { - super( dims ); - this.reader = reader; - this.file = file; - this.series = series; - this.channel = channel; - this.timepoint = timepoint; - this.type = type; - this.byteConverter = byteConverter; - } - - @Override - public RandomAccess< T > randomAccess() - { - return new VirtualRandomAccessLOCI(); - } - - @Override - public RandomAccess< T > randomAccess(Interval interval) - { - return randomAccess(); - } - - @Override - public T getType() - { - return type; - } - - private class VirtualRandomAccessLOCI extends Point implements RandomAccess< T > - { - - private byte[] buffer; - private T type; - private int currentZ = -1; - - private VirtualRandomAccessLOCI() - { - super( 3 ); - this.type = VirtualRandomAccessibleIntervalLOCI.this.type.createVariable(); - buffer = new byte[0]; - - } - - private void readIntoBuffer() - { - - VirtualRAIFactoryLOCI.setReaderFileAndSeriesIfNecessary( reader, file, series ); - - int siz = reader.getBitsPerPixel() / 8 * reader.getRGBChannelCount() * reader.getSizeX() - * reader.getSizeY(); - buffer = new byte[siz]; - -// System.out.println( "reading z plane " + position[2] + " from series " + series + " in file " + file.getAbsolutePath() ); - - // FIX for XYZ <-> XYT mixup in rare cases - int actualTP = (!reader.isOrderCertain() && reader.getSizeZ() <= 1 && reader.getSizeT() > 1 ) ? (int) position[2] : timepoint; - int actualZ = (!reader.isOrderCertain() && reader.getSizeZ() <= 1 && reader.getSizeT() > 1 ) ? timepoint : (int) position[2]; - - try - { - // the image is RGB -> we have to read bytes for all channels at once? - if (reader.getRGBChannelCount() == reader.getSizeC()) - reader.openBytes( reader.getIndex( actualZ, 0, actualTP), buffer ); - // normal image -> read specified channel - else - reader.openBytes( reader.getIndex( actualZ, channel, actualTP), buffer ); - } - catch ( FormatException | IOException e ) - { - e.printStackTrace(); - } - } - - @Override - public T get() - { - // prevent multithreaded overwriting of buffer - synchronized ( reader ) - { - if ( position[2] != currentZ || !VirtualRAIFactoryLOCI.checkReaderFileAndSeries( reader, file, series )) - { - currentZ = (int) position[2]; - readIntoBuffer(); - } - - int rgbOffset = 0; - if (reader.getRGBChannelCount() == reader.getSizeC()) - rgbOffset = channel * buffer.length / reader.getSizeC(); - - // pixel index (we do not care about bytesPerPixel here, byteCOnverter should take care of that) - final int i = (int) (rgbOffset + position[0] + position[1] * VirtualRandomAccessibleIntervalLOCI.this.dimension( 0 ) ); - byteConverter.accept( type, buffer, i ); - return this.type; - } - } - - @Override - public RandomAccess< T > copy() - { - return new VirtualRandomAccessLOCI(); - } - - } - -} diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/XmlIOFileMapImgLoaderLOCI2.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/XmlIOFileMapImgLoaderLOCI2.java index 3193afba..16188b83 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/XmlIOFileMapImgLoaderLOCI2.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/filemap2/XmlIOFileMapImgLoaderLOCI2.java @@ -32,13 +32,9 @@ import mpicbg.spim.data.XmlHelpers; import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; -import mpicbg.spim.data.generic.sequence.BasicViewDescription; import mpicbg.spim.data.generic.sequence.ImgLoaderIo; import mpicbg.spim.data.generic.sequence.XmlIoBasicImgLoader; import mpicbg.spim.data.sequence.ViewId; -import net.imglib2.util.Pair; -import net.imglib2.util.ValuePair; - @ImgLoaderIo( format = "spimreconstruction.filemap2", type = FileMapImgLoaderLOCI2.class ) @@ -57,27 +53,23 @@ public class XmlIOFileMapImgLoaderLOCI2 implements XmlIoBasicImgLoader< FileMapI @Override public Element toXml(FileMapImgLoaderLOCI2 imgLoader, File basePath) { - Map< ViewId, Pair< File, Pair< Integer, Integer > > > fileMap = imgLoader.getFileMap(); - final Element wholeElem = new Element( "ImageLoader" ); wholeElem.setAttribute( IMGLOADER_FORMAT_ATTRIBUTE_NAME, this.getClass().getAnnotation( ImgLoaderIo.class ).format() ); wholeElem.addContent( XmlHelpers.booleanElement( ZGROUPED_TAG, imgLoader.zGrouped ) ); + final Map< ViewId, FileMapEntry > fileMap = imgLoader.getFileMap(); final Element filesElement = new Element( FILES_TAG ); - - for ( ViewId vid : fileMap.keySet() ) - { - final Pair< File, Pair< Integer, Integer > > pair = fileMap.get( vid ); + fileMap.forEach( ( vid, entry ) -> { final Element fileMappingElement = new Element( FILE_MAPPING_TAG ); fileMappingElement.setAttribute( MAPPING_VS_TAG, Integer.toString( vid.getViewSetupId() ) ); fileMappingElement.setAttribute( MAPPING_TP_TAG, Integer.toString( vid.getTimePointId() ) ); - fileMappingElement.addContent( XmlHelpers.pathElement( MAPPING_FILE_TAG, pair.getA(), basePath ) ); - fileMappingElement.setAttribute( MAPPING_SERIES_TAG, Integer.toString( pair.getB().getA() ) ); - fileMappingElement.setAttribute( MAPPING_C_TAG, Integer.toString( pair.getB().getB() ) ); + fileMappingElement.addContent( XmlHelpers.pathElement( MAPPING_FILE_TAG, entry.file(), basePath ) ); + fileMappingElement.setAttribute( MAPPING_SERIES_TAG, Integer.toString( entry.series() ) ); + fileMappingElement.setAttribute( MAPPING_C_TAG, Integer.toString( entry.channel() ) ); filesElement.addContent( fileMappingElement ); - } + } ); // elem.addContent( XmlHelpers.pathElement( DIRECTORY_TAG, // imgLoader.getCZIFile().getParentFile(), basePath ) ); @@ -97,7 +89,7 @@ public FileMapImgLoaderLOCI2 fromXml(Element elem, File basePath, // final File path = loadPath( elem, DIRECTORY_TAG, basePath ); final Element fileMapElement = elem.getChild( FILES_TAG ); - final HashMap< BasicViewDescription< ? >, Pair< File, Pair< Integer, Integer > > > fileMap = new HashMap<>(); + final Map< ViewId, FileMapEntry > fileMap = new HashMap<>(); for ( Element e : fileMapElement.getChildren( FILE_MAPPING_TAG ) ) { @@ -107,11 +99,8 @@ public FileMapImgLoaderLOCI2 fromXml(Element elem, File basePath, int channel = Integer.parseInt( e.getAttribute( MAPPING_C_TAG ).getValue() ); File f = XmlHelpers.loadPath( e, MAPPING_FILE_TAG, basePath ); - BasicViewDescription< ? > vd = sequenceDescription.getViewDescriptions().get( new ViewId( tp, vs ) ); - Pair< File, Pair< Integer, Integer > > p = new ValuePair< File, Pair< Integer, Integer > >( f, - new ValuePair< Integer, Integer >( series, channel ) ); - - fileMap.put( vd, p ); + ViewId vd = new ViewId( tp, vs ); + fileMap.put( vd, new FileMapEntry( f, series, channel ) ); } return new FileMapImgLoaderLOCI2( fileMap, sequenceDescription, zGrouped ); diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/DefaultFlatfieldCorrectionWrappedImgLoader.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/DefaultFlatfieldCorrectionWrappedImgLoader.java index 6c9d4dd9..b44efe3f 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/DefaultFlatfieldCorrectionWrappedImgLoader.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/DefaultFlatfieldCorrectionWrappedImgLoader.java @@ -29,14 +29,13 @@ import mpicbg.spim.data.generic.sequence.ImgLoaderHint; import mpicbg.spim.data.generic.sequence.ImgLoaderHints; import mpicbg.spim.data.sequence.ImgLoader; -import mpicbg.spim.data.sequence.SequenceDescription; import mpicbg.spim.data.sequence.SetupImgLoader; -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 net.imglib2.Dimensions; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.converter.RealTypeConverters; import net.imglib2.img.Img; import net.imglib2.img.ImgFactory; import net.imglib2.img.array.ArrayImgFactory; @@ -46,10 +45,8 @@ import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.view.Views; -import net.preibisch.mvrecon.fiji.plugin.queryXML.GenericLoadParseQueryXML; import net.preibisch.mvrecon.fiji.plugin.queryXML.LoadParseQueryXML; import net.preibisch.mvrecon.fiji.spimdata.SpimData2; -import net.preibisch.mvrecon.fiji.spimdata.XmlIoSpimData2; import net.preibisch.mvrecon.fiji.spimdata.imgloaders.filemap2.FileMapImgLoaderLOCI2; import net.preibisch.mvrecon.process.fusion.FusionTools; @@ -140,7 +137,7 @@ public RandomAccessibleInterval< T > getImage(int timepointId, ImgLoaderHint... imgFactory = new CellImgFactory(); Img< T > loadedImg = imgFactory.create( rai, getImageType() ); - FileMapImgLoaderLOCI2.copy(Views.extendZero( rai ), loadedImg); + RealTypeConverters.copyFromTo( Views.extendZero( rai ), loadedImg ); rai = loadedImg; } diff --git a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/MultiResolutionFlatfieldCorrectionWrappedImgLoader.java b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/MultiResolutionFlatfieldCorrectionWrappedImgLoader.java index 76703cf0..47989bc2 100644 --- a/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/MultiResolutionFlatfieldCorrectionWrappedImgLoader.java +++ b/src/main/java/net/preibisch/mvrecon/fiji/spimdata/imgloaders/flatfield/MultiResolutionFlatfieldCorrectionWrappedImgLoader.java @@ -41,7 +41,9 @@ import net.imglib2.Dimensions; import net.imglib2.FinalDimensions; import net.imglib2.RandomAccess; +import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.converter.RealTypeConverters; import net.imglib2.img.Img; import net.imglib2.img.ImgFactory; import net.imglib2.img.array.ArrayImgFactory; @@ -220,7 +222,7 @@ public RandomAccessibleInterval< T > getImage(int timepointId, int level, ImgLoa imgFactory = new CellImgFactory(); Img< T > loadedImg = imgFactory.create( rai, getImageType() ); - FileMapImgLoaderLOCI2.copy(Views.extendZero( rai ), loadedImg); + RealTypeConverters.copyFromTo( Views.extendZero( rai ), loadedImg ); rai = loadedImg; }