From 7fdff9f49bd69f2ed9289e1f15327a0358115b72 Mon Sep 17 00:00:00 2001 From: Eugene Katrukha Date: Tue, 30 Apr 2024 13:07:55 +0200 Subject: [PATCH] added template class --- .../java/averagingND/IterativeAveraging.java | 378 ++++++++++-------- .../java/averagingND/TemplateAveraging.java | 306 ++++++++++++++ 2 files changed, 519 insertions(+), 165 deletions(-) create mode 100644 src/main/java/averagingND/TemplateAveraging.java diff --git a/src/main/java/averagingND/IterativeAveraging.java b/src/main/java/averagingND/IterativeAveraging.java index 14e09f6..27d3a7e 100644 --- a/src/main/java/averagingND/IterativeAveraging.java +++ b/src/main/java/averagingND/IterativeAveraging.java @@ -41,6 +41,9 @@ public class IterativeAveraging implements PlugIn, DialogListener { /** ND shift of each image **/ ArrayList shifts; + /** function holding information about current template **/ + TemplateAveraging template = null; + /** source of images * 0 - images currently open in ImageJ * 1 - tif files on disk **/ @@ -77,6 +80,9 @@ public class IterativeAveraging implements PlugIn, DialogListener { * **/ public int nConstrainReg = 0; + double [] lim_fractions = null; + FinalInterval limInterval = null; + /** choice UI for constrain type **/ Choice limitCh; @@ -92,14 +98,18 @@ public class IterativeAveraging implements PlugIn, DialogListener { /** format of the input dataset XYZTC **/ String sDims; + /** type of averaging aim + * 0 - average + * 1 - median + * 2 - zero masked average **/ + int nAveragingAim; + @Override public void run(String paramString) { int i,j,k, iter; int d; - double [] dLimits; - ArrayList> imgs_avrg_out; //double format formatting tool @@ -143,168 +153,12 @@ public void run(String paramString) { return; } - sDims = imageSet.sRefDims; - - nDimReg = sDims.length(); - if(imageSet.bMultiCh) - { - nDimReg--; //remove the C component - } - limName = new Label[nDimReg]; - limVal = new TextField[nDimReg]; - dLimits = new double [nDimReg]; - - final String[] sIniTemplate = new String[ ]{"Centered","Zero (top-left)"}; - final String[] limitsReg = new String[ ] {"No","by voxels", "by image fraction"}; - final GenericDialog gd1 = new GenericDialog( "Averaging parameters" ); - if(imageSet.bMultiCh) - { - final String[] channels = new String[ imageSet.nChannels]; - for ( int c = 0; c < channels.length; ++c ) - channels[ c ] = "use channel " + Integer.toString(c+1); - gd1.addChoice( "For alignment", channels, channels[ 0 ] ); - } - gd1.addChoice( "Initial template:", sIniTemplate, Prefs.get("RegisterNDFFT.IA.nIniTemplate", sIniTemplate[0]) ); - gd1.addNumericField("Number of iterations", Prefs.get("RegisterNDFFT.IA.nIterN",10),0); - gd1.addCheckbox("Use zero masked CC?", Prefs.get("RegisterNDFFT.IA.bExcludeZeros", false)); - gd1.addCheckbox("Show intermediate average?", Prefs.get("RegisterNDFFT.IA.bShowIntermediateAverage",false)); - gd1.addCheckbox("If yes, save intermediate on disk?", Prefs.get("RegisterNDFFT.IA.bSaveIntermediate",false)); - gd1.addCheckbox("Output registered inputs?", Prefs.get("RegisterNDFFT.IA.bOutputInput",false)); - String sCurrChoice = Prefs.get("RegisterNDFFT.IA.sConstrain", "No"); - gd1.addChoice("Constrain registration?", limitsReg, sCurrChoice); - limitCh = (Choice) gd1.getChoices().lastElement(); - for (d=0;d0) - { - DirectoryChooser dc = new DirectoryChooser ( "Choose a folder to save intermediate averages..." ); - sPathIntermediate = dc.getDirectory(); - if(sPathIntermediate == null) - return; - - } - - if(!imageSet.loadAllImages()) return; + if(nIterN>0) { IJ.log("Running for "+Integer.toString(nIterN)+" iterations."); @@ -317,9 +171,11 @@ public void run(String paramString) { //create a new shifted array of images buildShiftedIntervals(imageSet.imgs, imgs_shift,shifts); + + template = new TemplateAveraging(nAveragingAim); - ArrayList> sumAndCount = null; - sumAndCount = AverageWithoutZero.sumAndCountArray(imgs_shift); + //ArrayList> sumAndCount = null; + //sumAndCount = AverageWithoutZero.sumAndCountArray(imgs_shift); IntervalView currAverageImg; if(bIntermediateAverage && nIterN>0) @@ -382,12 +238,15 @@ public void run(String paramString) { IJ.showStatus("Averaging iteration "+Integer.toString(iter+1)+"..."); avrgCC = 0.0; iterStartT = System.currentTimeMillis(); + //new average (sum and count) + template.init(imgs_shift); //calculate shifts and CC values for(i=0;i initShifts(final ArrayList> imgs_in, int nMethod) @@ -705,6 +565,194 @@ public void processIntermediate(final int nIt) temp.show(); } } + + public boolean dialogSettings() + { + int d; + + //double format formatting tool + final DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator('.'); + final DecimalFormat df1 = new DecimalFormat ("#.#", symbols); + + sDims = imageSet.sRefDims; + + nDimReg = sDims.length(); + if(imageSet.bMultiCh) + { + nDimReg--; //remove the C component + } + + + limName = new Label[nDimReg]; + limVal = new TextField[nDimReg]; + double [] dLimits = new double [nDimReg]; + + final String[] sIniTemplate = new String[ ]{"Centered","Zero (top-left)"}; + final String[] sAveragingAim = new String[ ]{"Average","Median","Zero masked average"}; + final String[] limitsReg = new String[ ] {"No","by voxels", "by image fraction"}; + final GenericDialog gd1 = new GenericDialog( "Averaging parameters" ); + if(imageSet.bMultiCh) + { + final String[] channels = new String[ imageSet.nChannels]; + for ( int c = 0; c < channels.length; ++c ) + channels[ c ] = "use channel " + Integer.toString(c+1); + gd1.addChoice( "For alignment", channels, channels[ 0 ] ); + } + gd1.addChoice( "Initial template:", sIniTemplate, Prefs.get("RegisterNDFFT.IA.nIniTemplate", sIniTemplate[0]) ); + gd1.addNumericField("Number of iterations", Prefs.get("RegisterNDFFT.IA.nIterN",10),0); + gd1.addChoice( "Template calculation:", sAveragingAim, Prefs.get("RegisterNDFFT.IA.nAveragingAim", sAveragingAim[0]) ); + gd1.addCheckbox("Use zero masked CC?", Prefs.get("RegisterNDFFT.IA.bExcludeZeros", false)); + String sCurrChoice = Prefs.get("RegisterNDFFT.IA.sConstrain", "No"); + gd1.addChoice("Constrain registration?", limitsReg, sCurrChoice); + limitCh = (Choice) gd1.getChoices().lastElement(); + for (d=0;d0) + { + DirectoryChooser dc = new DirectoryChooser ( "Choose a folder to save intermediate averages..." ); + sPathIntermediate = dc.getDirectory(); + if(sPathIntermediate == null) + return false; + + } + return true; + + } + + @Override public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) { int d; diff --git a/src/main/java/averagingND/TemplateAveraging.java b/src/main/java/averagingND/TemplateAveraging.java new file mode 100644 index 0000000..20c1c13 --- /dev/null +++ b/src/main/java/averagingND/TemplateAveraging.java @@ -0,0 +1,306 @@ +package averagingND; + +import java.util.ArrayList; + +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.numeric.real.FloatType; +import net.imglib2.util.Intervals; +import net.imglib2.view.IntervalView; +import net.imglib2.view.Views; + +public class TemplateAveraging { + + /** array holding information about current template. + * In case of average, contains a sum of all pixels, + * in case of median - three imgs around the median + * in case of masked average - sum and count per pixel **/ + public ArrayList> current_stat = new ArrayList>(); + + + public IntervalView currentTemplate = null; + + /** possible types of ImageSet statistics stored **/ + public static final int AVERAGE=0, MEDIAN=1, MASKED_AVERAGE=2; + + /** specific type that is used to analyze data**/ + public int nStatType; + + /** if the object was initialized **/ + public boolean bInit = false; + + public int nImgN = 0; + + public FinalInterval unionInterval; + + public TemplateAveraging(final int nStatType_) + { + nStatType = nStatType_; + } + + /** initialize the object **/ + public void init(ArrayList> imgs_) + { + switch(nStatType) + { + case AVERAGE: + unionInterval = sumArray(imgs_, current_stat); + break; + case MEDIAN: + break; + case MASKED_AVERAGE: + unionInterval = sumAndCountArray(imgs_, current_stat); + break; + } + currentTemplate = null; + bInit = true; + nImgN = imgs_.size(); + } + + public IntervalView getTemplateForImage(RandomAccessibleInterval< FloatType > currentImage) + { + IntervalView out = null; + + if(!bInit) + { + System.out.println("Template object was not initialized!"); + return out; + } + + switch(nStatType) + { + case AVERAGE: + out = getTemplateForImageAverage(currentImage); + break; + case MEDIAN: + break; + case MASKED_AVERAGE: + out = getTemplateForImageMaskedAverage(currentImage); + break; + } + + return out; + } + + /** allocates memory for the current template **/ + void initCurrentTemplate() + { + final long [] origin = current_stat.get(0).minAsLongArray(); + final Img avrgImgArr = ArrayImgs.floats(current_stat.get(0).dimensionsAsLongArray()); + currentTemplate = Views.translate(avrgImgArr, origin ); + } + + /** returns current template for AVERAGE, + * i.e. sum - currentImage/number of images **/ + IntervalView getTemplateForImageAverage(final RandomAccessibleInterval< FloatType > currentImage) + { + + if(currentTemplate == null) + { + initCurrentTemplate(); + } + + final IntervalView removeInt = Views.interval(Views.extendZero(currentImage), currentTemplate); + final Cursor avrgC = currentTemplate.cursor(); + final Cursor remC = removeInt.cursor(); + final Cursor sumC = current_stat.get(0).cursor(); + + while(avrgC.hasNext()) + { + avrgC.fwd(); + remC.fwd(); + sumC.fwd(); + avrgC.get().set((sumC.get().get()-remC.get().get())/((float)nImgN)); + + } + + //return Views.zeroMin(avrgImg); + return currentTemplate; + } + + /** returns current template for MASKED_AVERAGE, + * i.e. sum - currentImage/updated count per pixel **/ + IntervalView getTemplateForImageMaskedAverage(final RandomAccessibleInterval< FloatType > currentImage) + { + + if(currentTemplate == null) + { + initCurrentTemplate(); + } + + final IntervalView removeInt = Views.interval(Views.extendZero(currentImage), currentTemplate); + final Cursor avrgC = currentTemplate.cursor(); + final Cursor remC = removeInt.cursor(); + final Cursor sumC = current_stat.get(0).cursor(); + final Cursor cntC = current_stat.get(1).cursor(); + float fCnt, fRem, fSum; + while(avrgC.hasNext()) + { + avrgC.fwd(); + remC.fwd(); + sumC.fwd(); + cntC.fwd(); + fSum = sumC.get().get(); + fRem = remC.get().get(); + fCnt = cntC.get().get(); + if(fRem>0.0f) + { + fSum-=fRem; + fCnt--; + } + + if (fCnt>0.5f) + { + avrgC.get().set(fSum/fCnt); + } + else + { + avrgC.get().set(0.0f); + } + } + return currentTemplate; + } + + + /** Provided with an ArrayList of RAIs, makes a new current_stat ArrayList with a single RAI, + * containing cumulative sum of all intensities at a current voxel/pixel location. + * Since input RAIs could be of different sizes/locations, the output size is made to include + * all of them, i.e. a hyper box that includes them all (stored in unionInterval) **/ + public static FinalInterval sumArray(final ArrayList> imgs, final ArrayList> out) + { + int i; + + final FinalInterval outUnionInterval = getUnionIntervalFromArray(imgs); + + final ArrayList> interv = new ArrayList>(); + + for(i=0;i> cursors = new ArrayList>(); + for(i=0;i sumImgArr = ArrayImgs.floats(outUnionInterval.dimensionsAsLongArray()); + + + long [] originCoord = outUnionInterval.minAsLongArray(); + + final IntervalView sumImg = Views.translate(sumImgArr, originCoord); + + + final Cursor sumC = sumImg.cursor(); + Cursor imgC; + double nSumVal; + while(sumC.hasNext()) + { + sumC.fwd(); + nSumVal = 0; + for(i=0;i> imgs, final ArrayList> out) + { + int i; + + final FinalInterval outUnionInterval = getUnionIntervalFromArray(imgs); + + + ArrayList> interv = new ArrayList>(); + + for(i=0;i> cursors = new ArrayList>(); + for(i=0;i sumImgArr = ArrayImgs.floats(outUnionInterval.dimensionsAsLongArray()); + final Img countImgArr = ArrayImgs.floats(outUnionInterval.dimensionsAsLongArray()); + + long [] originCoord = outUnionInterval.minAsLongArray(); + + final IntervalView sumImg = Views.translate(sumImgArr, originCoord); + final IntervalView countImg = Views.translate(countImgArr, originCoord); + + Cursor sumC = sumImg.cursor(); + Cursor cntC = countImg.cursor(); + Cursor imgC; + long nNumVal; + double nSumVal; + float nValCur; + + while(sumC.hasNext()) + { + sumC.fwd(); + cntC.fwd(); + nNumVal = 0; + nSumVal = 0; + for(i=0;i 0.0000001) + { + nNumVal++; + nSumVal += nValCur; + } + } + if(nNumVal > 0) + { + sumC.get().set((float)nSumVal); + cntC.get().set((float)nNumVal); + } + } + + out.clear(); + out.add(sumImg); + out.add(countImg); + return outUnionInterval; + + } + + /** returns an interval that encompasses all RAIs in the input ArrayList **/ + public static FinalInterval getUnionIntervalFromArray(ArrayList> imgs) + { + + if (imgs.size()==0) + return null; + FinalInterval out = new FinalInterval(imgs.get(0)); + + for(int i=1;i