From ecaf13ffde5a9fc7983c969450af558cd585eace Mon Sep 17 00:00:00 2001 From: Eugene Katrukha Date: Wed, 1 May 2024 13:31:37 +0200 Subject: [PATCH] virtualstack --- .../java/averagingND/FloatTiffImgWrap.java | 117 ++++++++++++++++ src/main/java/averagingND/GenNormCC.java | 23 ++- src/main/java/averagingND/ImageSet.java | 132 ++++++++++++++---- .../java/averagingND/IterativeAveraging.java | 72 +++++++--- src/test/java/tests/virtualWrapTest.java | 24 ++++ 5 files changed, 311 insertions(+), 57 deletions(-) create mode 100644 src/main/java/averagingND/FloatTiffImgWrap.java create mode 100644 src/test/java/tests/virtualWrapTest.java diff --git a/src/main/java/averagingND/FloatTiffImgWrap.java b/src/main/java/averagingND/FloatTiffImgWrap.java new file mode 100644 index 0000000..0c44ef8 --- /dev/null +++ b/src/main/java/averagingND/FloatTiffImgWrap.java @@ -0,0 +1,117 @@ +package averagingND; + +import ij.ImagePlus; +import net.imglib2.cache.img.CellLoader; +import net.imglib2.cache.img.ReadOnlyCachedCellImgFactory; +import net.imglib2.cache.img.ReadOnlyCachedCellImgOptions; +import net.imglib2.cache.img.SingleCellArrayImg; +import net.imglib2.img.Img; +import net.imglib2.type.numeric.real.FloatType; + +public class FloatTiffImgWrap { + + + public static Img< FloatType > wrapVirtualFloat(final ImagePlus imp, String sDims_) + { + String sDims = sDims_; + final int nDims = sDims.length(); + final long[] dimensions = new long[nDims]; + final int nBitD = imp.getBitDepth(); + for(int i=0;i loader = new CellLoader< FloatType >() + { + @Override + public void load( final SingleCellArrayImg< FloatType , ? > cell ) throws Exception + { + //final int z = ( int ) cell.min( 2 ); + int nCh = 1; + int nSl = 1; + int nTp = 1; + for(int i=2;i img = new ReadOnlyCachedCellImgFactory().create( +// dimensions, +// new FloatType(), +// loader, +// ReadOnlyCachedCellImgOptions.options().cellDimensions( cellDimensions ) ); + return new ReadOnlyCachedCellImgFactory().create( + dimensions, + new FloatType(), + loader, + ReadOnlyCachedCellImgOptions.options().cellDimensions( cellDimensions ) ); + } + //static long[] +} diff --git a/src/main/java/averagingND/GenNormCC.java b/src/main/java/averagingND/GenNormCC.java index efa3c3c..8990322 100644 --- a/src/main/java/averagingND/GenNormCC.java +++ b/src/main/java/averagingND/GenNormCC.java @@ -9,6 +9,8 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.algorithm.fft2.FFT; import net.imglib2.algorithm.fft2.FFTMethods; +import net.imglib2.converter.Converter; +import net.imglib2.converter.Converters; import net.imglib2.img.Img; import net.imglib2.img.ImgFactory; import net.imglib2.img.ImgView; @@ -17,6 +19,9 @@ import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.basictypeaccess.array.FloatArray; import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.img.imageplus.ImagePlusImg; +import net.imglib2.img.imageplus.ImagePlusImgFactory; +import net.imglib2.type.Type; import net.imglib2.type.numeric.complex.ComplexFloatType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.util.Intervals; @@ -170,12 +175,13 @@ public boolean caclulateGenNormCC(final RandomAccessibleInterval< FloatType > im //ImageJFunctions.show(padUnitTem).setTitle( "unipadded2" ); //squared image values - Img< FloatType > sqImg = ImgView.wrap(image).copy(); - Img< FloatType > sqTem = ImgView.wrap(template).copy(); - - sqImg.forEach(t-> t.mul(t.get())); - sqTem.forEach(t-> t.mul(t.get())); - + //Img< FloatType > sqImg = ImgView.wrap(image).copy(); + //Img< FloatType > sqTem = ImgView.wrap(template).copy(); + //sqImg.forEach(t-> t.mul(t.get())); + //sqTem.forEach(t-> t.mul(t.get())); + RandomAccessibleInterval< FloatType > sqImg = Converters.convert(image, ( in,out )-> {out.set(in.get()*in.get());}, new FloatType()); + RandomAccessibleInterval< FloatType > sqTem = Converters.convert(template, ( in,out )-> {out.set(in.get()*in.get());}, new FloatType()); + //padded squared images IntervalView< FloatType > padSqImg = Views.interval(Views.extendZero(sqImg),imgIntPad); IntervalView< FloatType > padSqTem = Views.interval(Views.extendZero(sqTem),temIntPad); @@ -200,12 +206,14 @@ public boolean caclulateGenNormCC(final RandomAccessibleInterval< FloatType > im FFTMethods.complexConjugate(sqTemplateFFT2); //multiplications + final Img< ComplexFloatType > I1F2F2 = multCompl(unImageFFT2,sqTemplateFFT2); + final Img< ComplexFloatType > deNOM = multCompl(unImageFFT2,unTemplateFFT2); final Img< ComplexFloatType > F1F2 = multCompl(imageFFT2,templateFFT2); final Img< ComplexFloatType > F1I2 = multCompl(imageFFT2,unTemplateFFT2); final Img< ComplexFloatType > I1F2 = multCompl(unImageFFT2,templateFFT2); final Img< ComplexFloatType > F1F1I2 = multCompl(sqImageFFT2,unTemplateFFT2); - final Img< ComplexFloatType > I1F2F2 = multCompl(unImageFFT2,sqTemplateFFT2); + //inverse FFT final Img< FloatType > invdeNOM = FFT.complexToReal(deNOM, factoryFloat, new FloatType()); @@ -458,4 +466,5 @@ public static Img< ComplexFloatType > multCompl(final Img< ComplexFloatType > im return output; } + } diff --git a/src/main/java/averagingND/ImageSet.java b/src/main/java/averagingND/ImageSet.java index 3ed29e1..f96452c 100644 --- a/src/main/java/averagingND/ImageSet.java +++ b/src/main/java/averagingND/ImageSet.java @@ -15,15 +15,29 @@ import ij.ImagePlus; import ij.WindowManager; import ij.measure.Calibration; - +import io.scif.config.SCIFIOConfig; +import io.scif.config.SCIFIOConfig.ImgMode; +import io.scif.img.ImgOpener; +import io.scif.img.SCIFIOImgPlus; +import net.imglib2.Cursor; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.converter.Converter; import net.imglib2.img.ImagePlusAdapter; +import net.imglib2.img.Img; +import net.imglib2.img.imageplus.ImagePlusImg; +import net.imglib2.img.imageplus.ImagePlusImgFactory; +import net.imglib2.type.Type; +import net.imglib2.type.numeric.ARGBType; +import net.imglib2.type.numeric.ComplexType; +import net.imglib2.type.numeric.integer.UnsignedByteType; +import net.imglib2.type.numeric.integer.UnsignedShortType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.view.Views; /** class containing a collection of images with info about them, * plus function to load them **/ -public class ImageSet { +public class ImageSet +{ /** original images (with full channels) **/ public ArrayList> imgs_multiCh; @@ -42,6 +56,7 @@ public class ImageSet { public int nChannels; public int nSlices; + int nTimePoints; public int alignChannel = 1; @@ -62,6 +77,8 @@ public class ImageSet { * 1 - images form disk **/ public int nSource; + public static final int OPENED = 0, LOAD_MEMORY = 1, CACHED = 2; + /** text representation of dimensions in the format of XYZCT **/ public String sRefDims; @@ -79,7 +96,7 @@ public ImageSet() // return; boolean initializeFromDisk(String sPath, String sFileExtension_) { - nSource = 1; + sFileExtension = sFileExtension_; // getting list of files filenames = null; @@ -121,7 +138,6 @@ boolean initializeFromDisk(String sPath, String sFileExtension_) boolean initializeFromOpenWindows() { - nSource = 0; idList = WindowManager.getIDList(); @@ -138,6 +154,7 @@ boolean initializeFromOpenWindows() } + @SuppressWarnings("unchecked") boolean loadAllImages() { int i; @@ -146,31 +163,57 @@ boolean loadAllImages() ImagePlus imageIn; int nTryImages; - if(nSource == 0) + if(nSource == OPENED) nTryImages = idList.length; else nTryImages = filenames.size(); + for(i=0;i imgF = FloatTiffImgWrap.wrapVirtualFloat(imageIn, sRefDimsIJ); + if(!bMultiCh) + { + imgs.add(imgF); + } + else + { + imgs_multiCh.add(imgF); + imgs.add(Views.hyperSlice(imgs_multiCh.get(i),2,alignChannel)); + } + } image_names.add(imageIn.getTitle()); @@ -180,8 +223,32 @@ boolean loadAllImages() { return false; } - } + } + + calculateLogMinMax(); + + IJ.showProgress(2,2); + IJ.showStatus("Loading images..done."); + if(nImageN<2) + { + IJ.error( "The plugin requires at least two images with the same dimensions. Aborting." ); + return false; + } + if(!bMultiCh) + { + IJ.log("Averaging "+ Integer.toString(nImageN) + " images."); + } + else + { + IJ.log("Averaging "+Integer.toString(nImageN) + " images with " + Integer.toString(nChannels) + " channels."); + IJ.log("Using channel "+Integer.toString(alignChannel+1) + " for alignment."); + } + return true; + } + + void calculateLogMinMax() + { //calculate min max long [] dimsMin = new long [nDim]; long [] dimsMax = new long [nDim]; @@ -196,7 +263,7 @@ boolean loadAllImages() imgs_multiCh.get(0).dimensions(dimsMin); imgs_multiCh.get(0).dimensions(dimsMax); } - for(i=1;i fullPath) } } + + protected static < T extends Type< T > > Img< FloatType > convertToFloat( + final Img< T > input, final Converter< T, FloatType > c ) + { + final ImagePlusImg< FloatType, ? > output = new ImagePlusImgFactory<>( new FloatType() ).create( input ); + + final Cursor< T > in = input.cursor(); + final Cursor< FloatType > out = output.cursor(); + + while ( in.hasNext() ) + { + in.fwd(); + out.fwd(); + + c.convert( in.get(), out.get() ); + } + + return output; + } + } diff --git a/src/main/java/averagingND/IterativeAveraging.java b/src/main/java/averagingND/IterativeAveraging.java index c3ecbf7..a48968a 100644 --- a/src/main/java/averagingND/IterativeAveraging.java +++ b/src/main/java/averagingND/IterativeAveraging.java @@ -21,11 +21,10 @@ import ij.measure.ResultsTable; import ij.plugin.PlugIn; -import net.imglib2.Cursor; import net.imglib2.FinalInterval; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.img.Img; -import net.imglib2.img.array.ArrayImgs; +import net.imglib2.type.NativeType; +import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.view.IntervalView; import net.imglib2.view.Views; @@ -108,6 +107,10 @@ public class IterativeAveraging implements PlugIn, DialogListener { * 2 - zero masked average **/ int nAveragingAim; + boolean bShowSD = false; + + boolean bLoadCached = false; + @Override public void run(String paramString) { @@ -122,9 +125,10 @@ public void run(String paramString) { DecimalFormat df = new DecimalFormat ("#.########", symbols); DecimalFormat df1 = new DecimalFormat ("#.#", symbols); - final String[] sInput = new String[2]; + final String[] sInput = new String[3]; sInput[0] = "All currently open images"; - sInput[1] = "Specify images in a folder"; + sInput[1] = "Tif files (high memory, fast)"; + sInput[2] = "Tif files (low memory, slow)"; final GenericDialog gdFiles = new GenericDialog( "Iterative averaging" ); @@ -143,14 +147,25 @@ public void run(String paramString) { //init arrays imgs_shift = new ArrayList>(); shifts = new ArrayList(); - - if(nInputType == 0) + imageSet.nSource = nInputType; + + if(nInputType == ImageSet.OPENED) { if(!imageSet.initializeFromOpenWindows()) return; + IJ.log("Using images already opened in ImageJ/Fiji."); } else { + if(nInputType == ImageSet.LOAD_MEMORY) + { + IJ.log("Loading all images to memory."); + } + else + { + IJ.log("Using cached reading of images."); + } + DirectoryChooser dc = new DirectoryChooser ( "Choose a folder with images.." ); String sPath = dc.getDirectory(); if(!imageSet.initializeFromDisk(sPath, ".tif")) @@ -363,25 +378,39 @@ public void run(String paramString) { IJ.log("Iteration count is equal to zero, no registration was done, just averaging."); } ptable.show("Results"); + ptable.save(sPathGeneralOutput+"Results.csv"); ptableCC.show("Average CC"); + ptableCC.save(sPathGeneralOutput+"Average_CC.csv"); shifts = maxAverCCshifts; //calculate final average image - IJ.log("calculating final average image.."); - + IJ.log("calculating final average image.."); imgs_avrg_out = getAlignedRAIs(shifts, true); - - IntervalView finalAver = FinalOutput.averageArray(imgs_avrg_out, bIgnoreZeroInAveraging); - - MiscUtils.wrapFloatImgCal(finalAver,"final_average_"+Integer.toString(nIterMax),imageSet.cal,imageSet.bMultiCh).show(); + String sOutFinalName = ""; + switch(nAveragingAim) + { + case TemplateAveraging.AVERAGE: + sOutFinalName ="final_avg_"; + break; + case TemplateAveraging.MASKED_AVERAGE: + sOutFinalName ="final_mask_avg_"; + break; + } + sOutFinalName = sOutFinalName +Integer.toString(nIterMax); + ImagePlus tempFin = MiscUtils.wrapFloatImgCal(finalAver,sOutFinalName,imageSet.cal,imageSet.bMultiCh); + IJ.saveAsTiff(tempFin, sPathGeneralOutput+sOutFinalName); IJ.log("...done."); //calculate STD image - IJ.log("calculating final standard deviation image.."); - IntervalView finalSTD = FinalOutput.stdArray(imgs_avrg_out, finalAver, bIgnoreZeroInAveraging); - MiscUtils.wrapFloatImgCal(finalSTD,"final_std_"+Integer.toString(nIterMax),imageSet.cal,imageSet.bMultiCh).show(); - IJ.log("...done."); - + if(bShowSD) + { + IJ.log("calculating final standard deviation image.."); + String sSDName = "final_std_"+Integer.toString(nIterMax); + IntervalView finalSTD = FinalOutput.stdArray(imgs_avrg_out, finalAver, bIgnoreZeroInAveraging); + ImagePlus finSD = MiscUtils.wrapFloatImgCal(finalSTD,sSDName,imageSet.cal,imageSet.bMultiCh); + IJ.saveAsTiff(finSD, sPathGeneralOutput+sSDName); + IJ.log("...done."); + } if(bOutputInput) { @@ -607,6 +636,7 @@ public boolean dialogSettings() gd1.addMessage("Output:"); gd1.addCheckbox("Save intermediates?", Prefs.get("RegisterNDFFT.IA.bSaveIntermediate",false)); gd1.addCheckbox("Save registered inputs?", Prefs.get("RegisterNDFFT.IA.bOutputInput",false)); + gd1.addCheckbox("Save SD image?", Prefs.get("RegisterNDFFT.IA.bShowSD",false)); gd1.addDialogListener(this); gd1.showDialog(); @@ -717,9 +747,13 @@ public boolean dialogSettings() bSaveIntermediate = gd1.getNextBoolean(); Prefs.set("RegisterNDFFT.IA.bSaveIntermediate", bSaveIntermediate); + bOutputInput = gd1.getNextBoolean(); Prefs.set("RegisterNDFFT.IA.bOutputInput", bOutputInput); - + + bShowSD = gd1.getNextBoolean(); + Prefs.set("RegisterNDFFT.IA.bShowSD", bShowSD); + DirectoryChooser dc = new DirectoryChooser ( "Choose a folder to save output..." ); sPathGeneralOutput = dc.getDirectory(); if(sPathGeneralOutput == null) diff --git a/src/test/java/tests/virtualWrapTest.java b/src/test/java/tests/virtualWrapTest.java new file mode 100644 index 0000000..73b6b46 --- /dev/null +++ b/src/test/java/tests/virtualWrapTest.java @@ -0,0 +1,24 @@ +package tests; + +import averagingND.FloatTiffImgWrap; +import averagingND.MiscUtils; +import ij.IJ; +import ij.ImageJ; +import ij.ImagePlus; +import net.imglib2.img.Img; +import net.imglib2.img.display.imagej.ImageJFunctions; +import net.imglib2.type.numeric.real.FloatType; + + +public class virtualWrapTest +{ + public static void main( final String[] args ) + { + + new ImageJ(); + ImagePlus imageIn = IJ.openVirtual("/home/eugene/Desktop/projects/UnequalTiffs/BB/001f.tif"); + Img< FloatType >img = FloatTiffImgWrap.wrapVirtualFloat(imageIn, MiscUtils.getDimensionsTextImageJ(imageIn)); + ImageJFunctions.show(img, "test_raw"); + + } +}