66import java .util .ArrayList ;
77import java .util .Arrays ;
88import java .util .Collection ;
9+ import java .util .Collections ;
910import java .util .HashMap ;
11+ import java .util .HashSet ;
1012import java .util .List ;
1113import java .util .Map ;
14+ import java .util .Set ;
1215import java .util .concurrent .Callable ;
1316import java .util .function .Function ;
1417
18+ import mpicbg .spim .data .generic .base .Entity ;
19+ import mpicbg .spim .data .registration .ViewRegistrations ;
20+ import mpicbg .spim .data .sequence .SequenceDescription ;
21+ import net .imglib2 .util .Pair ;
22+ import net .imglib2 .util .ValuePair ;
23+ import net .preibisch .mvrecon .process .interestpointregistration .pairwise .constellation .grouping .Group ;
1524import org .janelia .saalfeldlab .n5 .Compression ;
1625import org .janelia .saalfeldlab .n5 .DataType ;
1726import org .janelia .saalfeldlab .n5 .N5Writer ;
@@ -117,7 +126,10 @@ public class CreateFusionContainer extends AbstractBasic implements Callable<Voi
117126 @ Option (names = { "--group" }, description = "Container group path" )
118127 private String groupPath = "" ;
119128
120- URI outPathURI = null , xmlOutURI = null ;
129+ private URI outPathURI = null , xmlOutURI = null ;
130+ private double [] cal = new double [] { 1 , 1 , 1 };
131+ private String calUnit = "micrometer" ;
132+ private double avgAnisotropy = Double .NaN ;
121133
122134 /**
123135 * @return container group path always terminated with a '/'
@@ -376,34 +388,29 @@ else if ( storageType == StorageFormat.N5 || storageType == StorageFormat.ZARR )
376388 final Function <Integer , AffineTransform3D > levelToMipmapTransform =
377389 (level ) -> MipmapTransforms .getMipmapTransformDefault ( mrInfo [level ].absoluteDownsamplingDouble () );
378390
391+ updateAnisotropyAndCalibration (dataGlobal , viewIdsGlobal );
379392 // extract the resolution of the s0 export
380- final VoxelDimensions vx = dataGlobal .getSequenceDescription ().getViewSetupsOrdered ().iterator ().next ().getVoxelSize ();
381- final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( vx );
393+ final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( cal , avgAnisotropy , Double .NaN );
382394
383- System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + "micrometer" ); //vx.unit() might not be OME-ZARR compatiblevx.unit() );
395+ System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + calUnit );
384396
385397 // create metadata
386398 final OmeNgffMultiScaleMetadata [] meta = OMEZarrAttibutes .createOMEZarrMetadata (
387399 5 , // int n
388400 getContainerGroupPath (), // String name, I also saw "/"
389401 resolutionS0 , // double[] resolutionS0,
390- "micrometer" , //vx.unit() might not be OME-ZARR compatible // String unitXYZ, // e.g micrometer
402+ calUnit , //vx.unit() might not be OME-ZARR compatible // String unitXYZ, // e.g micrometer
391403 mrInfos [ 0 ].length , // int numResolutionLevels,
392404 (level ) -> "/" + level , // OME-ZARR metadata will be created relative to the provided group
393405 levelToMipmapTransform );
394406
395407 // save metadata
396-
397- //org.janelia.saalfeldlab.n5.universe.metadata.ome.ngff.v04.OmeNgffMetadata
398- // for this to work you need to register an adapter in the N5Factory class
399- // final GsonBuilder builder = new GsonBuilder().registerTypeAdapter( CoordinateTransformation.class, new CoordinateTransformationAdapter() );
400408 driverVolumeWriter .setAttribute ( getContainerGroupPath (), "multiscales" , meta );
401409 }
402410
403411 if ( bdv )
404412 {
405413 System .out .println ( "Creating BDV compatible container at '" + outPathURI + "' ... " );
406-
407414 if ( storageType == StorageFormat .N5 )
408415 driverVolumeWriter .setAttribute ( getContainerGroupPath (), "Bigstitcher-Spark/FusionFormat" , "BDV/N5" );
409416 else if ( storageType == StorageFormat .ZARR )
@@ -422,14 +429,12 @@ else if ( storageType == StorageFormat.ZARR )
422429 tps .add ( new TimePoint ( t ) );
423430
424431 // extract the resolution of the s0 export
425- // TODO: this is inaccurate, we should actually estimate it from the final transformn that is applied
426- // TODO: this is a hack (returns 1,1,1) so the export downsampling pyramid is working
427- final VoxelDimensions vx = new FinalVoxelDimensions ( "micrometer" , new double [] { 1 , 1 , 1 } );// dataGlobal.getSequenceDescription().getViewSetupsOrdered().iterator().next().getVoxelSize();
428- final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( vx );
432+
433+ final double [] resolutionS0 = OMEZarrAttibutes .getResolutionS0 ( cal , avgAnisotropy , Double .NaN );
429434
430435 System .out .println ( "Resolution of level 0: " + Util .printCoordinates ( resolutionS0 ) + " " + "m" ); //vx.unit() might not be OME-ZARR compatiblevx.unit() );
431436
432- final VoxelDimensions vxNew = new FinalVoxelDimensions ( "micrometer" , resolutionS0 );
437+ final VoxelDimensions vxNew = new FinalVoxelDimensions ( calUnit , resolutionS0 );
433438
434439 for ( int c = 0 ; c < numChannels ; ++c )
435440 {
@@ -535,6 +540,31 @@ else if ( storageType == StorageFormat.N5 || storageType == StorageFormat.HDF5 )
535540 return null ;
536541 }
537542
543+ private void updateAnisotropyAndCalibration ( SpimData2 dataGlobal , List <ViewId > viewIdsGlobal )
544+ {
545+ ViewRegistrations registrations = dataGlobal .getViewRegistrations ();
546+ // get all view descriptions
547+ List <ViewDescription > vds = SpimData2 .getAllViewDescriptionsSorted (dataGlobal , viewIdsGlobal );
548+ // group by timepoint and channel
549+ Set <Class <? extends Entity >> groupingFactors = new HashSet <>(Arrays .asList (TimePoint .class , Channel .class ));
550+ List <Group <ViewDescription >> fusionGroups = Group .splitBy ( vds , groupingFactors );
551+ Pair <double [], String > calAndUnit = fusionGroups .stream ().findFirst ()
552+ .map (group -> TransformationTools .computeAverageCalibration (group , registrations ))
553+ .orElse (new ValuePair <>(new double []{ 1 , 1 , 1 }, "micrometer" ));
554+ cal = calAndUnit .getA ();
555+ calUnit = calAndUnit .getB ();
556+
557+ if (preserveAnisotropy ) {
558+ if (!Double .isNaN (this .anisotropyFactor )) {
559+ avgAnisotropy = this .anisotropyFactor ;
560+ } else {
561+ avgAnisotropy = TransformationTools .getAverageAnisotropyFactor (dataGlobal , viewIdsGlobal );
562+ }
563+ } else {
564+ avgAnisotropy = Double .NaN ;
565+ }
566+ }
567+
538568 public static void main (final String ... args ) throws SpimDataException
539569 {
540570 System .out .println (Arrays .toString (args ));
0 commit comments