77import java .util .Arrays ;
88import java .util .Collection ;
99import java .util .HashMap ;
10+ import java .util .HashSet ;
1011import java .util .List ;
1112import java .util .Map ;
13+ import java .util .Set ;
1214import java .util .concurrent .Callable ;
1315import java .util .function .Function ;
1416
17+ import mpicbg .spim .data .generic .base .Entity ;
18+ import mpicbg .spim .data .registration .ViewRegistrations ;
19+ import net .imglib2 .util .Pair ;
20+ import net .imglib2 .util .ValuePair ;
21+ import net .preibisch .mvrecon .process .interestpointregistration .pairwise .constellation .grouping .Group ;
1522import org .janelia .saalfeldlab .n5 .Compression ;
1623import org .janelia .saalfeldlab .n5 .DataType ;
1724import org .janelia .saalfeldlab .n5 .N5Writer ;
@@ -59,8 +66,6 @@ public class CreateFusionContainer extends AbstractBasic implements Callable<Voi
5966{
6067 private static final long serialVersionUID = -9140450542904228386L ;
6168
62- public enum Compressions { Lz4 , Gzip , Zstandard , Blosc , Bzip2 , Xz , Raw };
63-
6469 @ Option (names = { "-o" , "--outputPath" }, required = true , description = "OME-ZARR/N5/HDF5 path for saving, e.g. -o /home/fused.zarr, file:/home/fused.n5 or e.g. s3://myBucket/data.zarr" )
6570 private String outputPathURIString = null ;
6671
@@ -70,7 +75,7 @@ public enum Compressions { Lz4, Gzip, Zstandard, Blosc, Bzip2, Xz, Raw };
7075
7176 @ Option (names = {"-c" , "--compression" }, defaultValue = "Zstandard" , showDefaultValue = CommandLine .Help .Visibility .ALWAYS ,
7277 description = "Dataset compression" )
73- private Compressions compression = null ;
78+ private Compressions compressionType = null ;
7479
7580 @ Option (names = {"-cl" , "--compressionLevel" }, description = "compression level, if supported by the codec (default: gzip 1, Zstandard 3, xz 6)" )
7681 private Integer compressionLevel = null ;
@@ -116,7 +121,10 @@ public enum Compressions { Lz4, Gzip, Zstandard, Blosc, Bzip2, Xz, Raw };
116121 @ Option (names = { "--anisotropyFactor" }, description = "define the anisotropy factor if preserveAnisotropy is set to true (default: compute from data)" )
117122 private double anisotropyFactor = Double .NaN ;
118123
119- URI outPathURI = null , xmlOutURI = null ;
124+ private URI outPathURI = null , xmlOutURI = null ;
125+ private double [] cal = new double [] { 1 , 1 , 1 };
126+ private String calUnit = "micrometer" ;
127+ private double avgAnisotropy = Double .NaN ;
120128
121129 @ Override
122130 public Void call () throws Exception
@@ -215,9 +223,9 @@ else if ( numTimepoints > numTimepointsXML )
215223 System .out .println ( "Fusion target: " + boundingBox .getTitle () + ": " + Util .printInterval ( boundingBox ) + " with blocksize " + Util .printCoordinates ( blockSize ) );
216224
217225 // compression and data type
218- final Compression compression = N5Util .getCompression ( this .compression , this .compressionLevel );
226+ final Compression compression = N5Util .getCompression ( this .compressionType , this .compressionLevel );
219227
220- System .out .println ( "Compression: " + this .compression );
228+ System .out .println ( "Compression: " + this .compressionType );
221229 System .out .println ( "Compression level: " + ( compressionLevel == null ? "default" : compressionLevel ) );
222230
223231 final DataType dt ;
@@ -362,29 +370,23 @@ else if ( storageType == StorageFormat.N5 || storageType == StorageFormat.ZARR )
362370 final Function <Integer , AffineTransform3D > levelToMipmapTransform =
363371 (level ) -> MipmapTransforms .getMipmapTransformDefault ( mrInfo [level ].absoluteDownsamplingDouble () );
364372
373+ updateAnisotropyAndCalibration (dataGlobal , viewIdsGlobal );
365374 // extract the resolution of the s0 export
366- // TODO: this is inaccurate, we should actually estimate it from the final transformn that is applied
367- // TODO: this is a hack (returns 1,1,1) so the export downsampling pyramid is working
368- final VoxelDimensions vx = dataGlobal .getSequenceDescription ().getViewSetupsOrdered ().iterator ().next ().getVoxelSize ();
369- final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( vx );
375+ final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( cal , avgAnisotropy , Double .NaN );
370376
371- System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + "micrometer" ); //vx.unit() might not be OME-ZARR compatiblevx.unit() );
377+ System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + calUnit );
372378
373379 // create metadata
374380 final OmeNgffMultiScaleMetadata [] meta = OMEZarrAttibutes .createOMEZarrMetadata (
375381 5 , // int n
376382 "/" , // String name, I also saw "/"
377383 resolutionS0 , // double[] resolutionS0,
378- "micrometer" , //vx.unit() might not be OME-ZARR compatible // String unitXYZ, // e.g micrometer
384+ calUnit , //vx.unit() might not be OME-ZARR compatible // String unitXYZ, // e.g micrometer
379385 mrInfos [ 0 ].length , // int numResolutionLevels,
380386 levelToName ,
381387 levelToMipmapTransform );
382388
383389 // save metadata
384-
385- //org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadata
386- // for this to work you need to register an adapter in the N5Factory class
387- // final GsonBuilder builder = new GsonBuilder().registerTypeAdapter( CoordinateTransformation.class, new CoordinateTransformationAdapter() );
388390 driverVolumeWriter .setAttribute ( "/" , "multiscales" , meta );
389391 }
390392
@@ -410,12 +412,12 @@ else if ( storageType == StorageFormat.ZARR )
410412 tps .add ( new TimePoint ( t ) );
411413
412414 // extract the resolution of the s0 export
413- final VoxelDimensions vx = dataGlobal . getSequenceDescription (). getViewSetupsOrdered (). iterator (). next (). getVoxelSize ();
414- final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( vx );
415+
416+ final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( cal , avgAnisotropy , Double . NaN );
415417
416418 System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + "m" ); //vx.unit() might not be OME-ZARR compatiblevx.unit() );
417419
418- final VoxelDimensions vxNew = new FinalVoxelDimensions ( "micrometer" , resolutionS0 );
420+ final VoxelDimensions vxNew = new FinalVoxelDimensions ( calUnit , resolutionS0 );
419421
420422 for ( int c = 0 ; c < numChannels ; ++c )
421423 {
@@ -441,7 +443,7 @@ else if ( storageType == StorageFormat.ZARR )
441443 for ( int t = 0 ; t < numTimepoints ; ++t )
442444 {
443445 final OMEZARREntry omeZarrEntry = new OMEZARREntry (
444- mrInfos [ 0 ][ 0 ].dataset .substring (0 , mrInfos [ 0 ][ 0 ].dataset .lastIndexOf ( "/" ) ),
446+ mrInfos [ t ][ c ].dataset .substring (0 , mrInfos [ t ][ c ].dataset .lastIndexOf ( "/" ) ),
445447 new int [] { c , t } );
446448
447449 viewIdToPath .put ( new ViewId ( t , c ), omeZarrEntry );
@@ -521,16 +523,35 @@ else if ( storageType == StorageFormat.N5 || storageType == StorageFormat.HDF5 )
521523 return null ;
522524 }
523525
524- public static void main ( final String ... args ) throws SpimDataException
526+ private void updateAnisotropyAndCalibration ( SpimData2 dataGlobal , List < ViewId > viewIdsGlobal )
525527 {
528+ ViewRegistrations registrations = dataGlobal .getViewRegistrations ();
529+ // get all view descriptions
530+ List <ViewDescription > vds = SpimData2 .getAllViewDescriptionsSorted (dataGlobal , viewIdsGlobal );
531+ // group by timepoint and channel
532+ Set <Class <? extends Entity >> groupingFactors = new HashSet <>(Arrays .asList (TimePoint .class , Channel .class ));
533+ List <Group <ViewDescription >> fusionGroups = Group .splitBy ( vds , groupingFactors );
534+ Pair <double [], String > calAndUnit = fusionGroups .stream ().findFirst ()
535+ .map (group -> TransformationTools .computeAverageCalibration (group , registrations ))
536+ .orElse (new ValuePair <>(new double []{ 1 , 1 , 1 }, "micrometer" ));
537+ cal = calAndUnit .getA ();
538+ calUnit = calAndUnit .getB ();
539+
540+ if (preserveAnisotropy ) {
541+ if (!Double .isNaN (this .anisotropyFactor )) {
542+ avgAnisotropy = this .anisotropyFactor ;
543+ } else {
544+ avgAnisotropy = TransformationTools .getAverageAnisotropyFactor (dataGlobal , viewIdsGlobal );
545+ }
546+ } else {
547+ avgAnisotropy = Double .NaN ;
548+ }
549+ }
526550
527- //final XmlIoSpimData io = new XmlIoSpimData();
528- //final SpimData spimData = io.load( "/Users/preibischs/Documents/Microscopy/Stitching/Truman/standard/output/dataset.xml" );
529- //BdvFunctions.show( spimData );
530- //SimpleMultiThreading.threadHaltUnClean();
531-
551+ public static void main (final String ... args ) throws SpimDataException
552+ {
532553 System .out .println (Arrays .toString (args ));
533554
534555 System .exit (new CommandLine (new CreateFusionContainer ()).execute (args ));
535556 }
536- }
557+ }
0 commit comments