diff --git a/README.md b/README.md deleted file mode 100644 index ed77e05..0000000 --- a/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Colocalisation Analysis - -[![Join the chat at https://gitter.im/fiji/Colocalisation_Analysis](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fiji/Colocalisation_Analysis?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Coloc 2 is Fiji's plugin for colocalization analysis. It implements -and performs the pixel intensity correlation over space methods of Pearson, -Manders, Costes, Li and more, for scatterplots, analysis, automatic thresholding -and statistical significance testing. - -Also included here are the old no longer supported plugins: -Colocalization Threshold and Colocalization Test -We only use these for comparison with Coloc_2, -and don't suggest you actually use them for real work. - -For more details, see http://imagej.net/Coloc_2 diff --git a/pom.xml b/pom.xml index 14a27c9..ef3fb61 100644 --- a/pom.xml +++ b/pom.xml @@ -1,175 +1,149 @@ - - - 4.0.0 - - - org.scijava - pom-scijava - 16.1.0 - - - - sc.fiji - Colocalisation_Analysis - 3.0.1-SNAPSHOT - - Coloc 2 - Fiji's plugin for colocalization analysis. - https://imagej.net/Coloc_2 - 2009 - - Fiji - http://fiji.sc/ - - - - GNU General Public License v3+ - http://www.gnu.org/licenses/gpl.html - repo - - - - - - chalkie666 - Daniel James White - http://imagej.net/User:White - - lead - reviewer - support - maintainer - - - - tomka - Tom Kazimiers - http://imagej.net/User:Kazimiers - - lead - debugger - reviewer - - - - etarena - Ellen Arena - http://imagej.net/User:Etarena - - developer - debugger - reviewer - support - - - - ctrueden - Curtis Rueden - http://imagej.net/User:Rueden - - maintainer - - - - - - Johannes Schindelin - http://imagej.net/User:Schindelin - founder - dscho - - - Jan Eglinger - http://imagej.net/User:Eglinger - imagejan - - - Leonardo Guizzetti - leonardicus - - - Mark Hiner - http://imagej.net/User:Hinerm - hinerm - - - Jean-Yves Tinevez - http://imagej.net/User:JeanYvesTinevez - tinevez - - - - - - ImageJ Forum - http://forum.imagej.net/ - - - - - scm:git:git://github.com/fiji/Colocalisation_Analysis - scm:git:git@github.com:fiji/Colocalisation_Analysis - HEAD - https://github.com/fiji/Colocalisation_Analysis - - - github.com - https://github.com/fiji/Colocalisation_Analysis - - - Travis CI - https://travis-ci.org/fiji/Colocalisation_Analysis - - - - gpl_v3 - Fiji developers. - - - - - imagej.public - http://maven.imagej.net/content/groups/public - - - - - - - sc.fiji - fiji-lib - - - - - net.imagej - ij - - - - - net.imglib2 - imglib2 - - - net.imglib2 - imglib2-algorithm - - - net.imglib2 - imglib2-ij - - - - - com.itextpdf - itextpdf - - - - junit - junit - test - - - + + + 4.0.0 + + + org.scijava + pom-scijava + 19.2.0 + + + + ch.epfl.biop + 1.0.0 + + B_Run_Macro + https://biop.epfl.ch/ + 2017 + + BIOP + https://biop.epfl.ch + + + + GNU General Public License v3+ + http://www.gnu.org/licenses/gpl.html + repo + + + + + + chalkie666 + Daniel James White + http://imagej.net/User:White + + lead + reviewer + support + maintainer + + + + tomka + Tom Kazimiers + http://imagej.net/User:Kazimiers + + lead + debugger + reviewer + + + + etarena + Ellen Arena + http://imagej.net/User:Etarena + + developer + debugger + reviewer + support + + + + ctrueden + Curtis Rueden + http://imagej.net/User:Rueden + + maintainer + + + + + + Johannes Schindelin + http://imagej.net/User:Schindelin + founder + dscho + + + Jan Eglinger + http://imagej.net/User:Eglinger + imagejan + + + Leonardo Guizzetti + leonardicus + + + Mark Hiner + http://imagej.net/User:Hinerm + hinerm + + + Jean-Yves Tinevez + http://imagej.net/User:JeanYvesTinevez + tinevez + + + + + + ImageJ Forum + http://forum.imagej.net/ + + + + + HEAD + https://c4science.ch/source/ijp-biop-run-macro.git + + + c4science + https://c4science.ch/source/ijp-biop-run-macro.git + + + None + NONE + + + + gpl_v3 + BIOP + C:/Fiji/ + + + + + imagej.public + http://maven.imagej.net/content/groups/public + + + + + + + + + + + net.imglib2 + imglib2-ij + + + + + + B_Run_Macro + Macro Runner command to work with SciJava Parameters + diff --git a/src/main/java/ch/epfl/biop/macrorunner/B_Run_Macro.java b/src/main/java/ch/epfl/biop/macrorunner/B_Run_Macro.java new file mode 100644 index 0000000..75deaed --- /dev/null +++ b/src/main/java/ch/epfl/biop/macrorunner/B_Run_Macro.java @@ -0,0 +1,36 @@ +package ch.epfl.biop.macrorunner; + +import java.io.File; +import java.io.FileNotFoundException; + +import javax.script.ScriptException; + +import org.scijava.command.Command; +import org.scijava.log.LogService; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.script.ScriptService; + +@Plugin(type= Command.class, menuPath="Plugins>BIOP>Macro>BIOP Run Macro...") +public class B_Run_Macro implements Command { + + @Parameter + private File macro_file; + + @Parameter + private LogService logService; + + @Parameter + private ScriptService scriptService; + + @Override + public void run() { + try { + scriptService.run(macro_file, true); + } catch (FileNotFoundException | ScriptException e) { + // TODO Auto-generated catch block + logService.error(e.toString()); + } + } + +} diff --git a/src/main/java/net/imglib2/PairIterator.java b/src/main/java/net/imglib2/PairIterator.java deleted file mode 100644 index 2dc0f35..0000000 --- a/src/main/java/net/imglib2/PairIterator.java +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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.imglib2; - -/** - * An iterator over pairs of types. - * - * @author "Johannes Schindelin" - * - * @param - */ -public interface PairIterator { - - /** - * Returns whether there are pairs left. - * - * @return true if there are pairs left. - */ - boolean hasNext(); - - /** - * Resets the iterator to just before the first element. - */ - void reset(); - - /** - * Go to the next pair. - */ - void fwd(); - - /** - * Return the first value of the pair. - * - * @return the first value of the pair - */ - T getFirst(); - - /** - * Return the second value of the pair. - * - * @return the second value of the pair - */ - T getSecond(); - -} diff --git a/src/main/java/net/imglib2/PredicateCursor.java b/src/main/java/net/imglib2/PredicateCursor.java deleted file mode 100644 index a899512..0000000 --- a/src/main/java/net/imglib2/PredicateCursor.java +++ /dev/null @@ -1,182 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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.imglib2; - -import java.util.NoSuchElementException; - -import net.imglib2.predicate.Predicate; -import net.imglib2.type.Type; - -/** - * The PredicateCursor traverses a whole image but only returns - * those pixels for which the Predicate returns true. There is - * little sense to make this less than a LocalizableCursor - */ -public class PredicateCursor> implements Cursor { - // the condition on which a position is valid - final protected Predicate predicate; - // the cursor driven by the evaluation of the predicate - final protected Cursor cursor; - // indicate if the next element has already been looked up - protected boolean lookedForNext = false; - // true if a next element was found after a look-up - protected boolean hasNext = false; - - public PredicateCursor(final Cursor cursor, - final Predicate predicate) { - this.cursor = cursor; - this.predicate = predicate; - } - - /** - * Walks to the next valid elements and stores them in member - * variables cachedType1 and cachedType2. - * - * @return true if a next element was found, false otherwise - */ - protected boolean findNext() { - boolean found = false; - while( cursor.hasNext() ) { - cursor.fwd(); - if ( predicate.test(cursor) ) { - found = true; - break; - } - } - hasNext = found; - return found; - } - - @Override - public boolean hasNext() { - // did we already check for a next element without doing a fwd()? - if ( lookedForNext ) - return hasNext; - - // indicate that we will already move the cursor to the next element - lookedForNext = true; - - return findNext(); - } - - @Override - public void fwd() { - /* If we did not check for a next valid element before, - * walk to the next element now (if there is any). - */ - if ( ! lookedForNext ) - findNext(); - - /* Since we have manually forwarded the cursor, the cached - * information is not valid any more - */ - lookedForNext = false; - } - - @Override - public void jumpFwd(long num) { - while (num > 0) { - fwd(); - } - } - - @Override - public T next() { - if ( hasNext() ) { - fwd(); - return get(); - } else { - throw new NoSuchElementException(); - } - } - - @Override - public void remove() { - cursor.remove(); - } - - @Override - public void reset() { - cursor.reset(); - lookedForNext = false; - } - - @Override - public double getDoublePosition(int arg0) { - return cursor.getDoublePosition(arg0); - } - - @Override - public float getFloatPosition(int arg0) { - return cursor.getFloatPosition(arg0); - } - - @Override - public void localize(float[] arg0) { - cursor.localize(arg0); - } - - @Override - public void localize(double[] arg0) { - cursor.localize(arg0); - } - - @Override - public int numDimensions() { - return cursor.numDimensions(); - } - - @Override - public Sampler copy() { - return cursor.copy(); - } - - @Override - public T get() { - return cursor.get(); - } - - @Override - public int getIntPosition(int arg0) { - return cursor.getIntPosition(arg0); - } - - @Override - public long getLongPosition(int arg0) { - return cursor.getLongPosition(arg0); - } - - @Override - public void localize(int[] arg0) { - cursor.localize(arg0); - } - - @Override - public void localize(long[] arg0) { - cursor.localize(arg0); - } - - @Override - public Cursor copyCursor() { - return new PredicateCursor( cursor.copyCursor(), predicate ); - } -} diff --git a/src/main/java/net/imglib2/TwinCursor.java b/src/main/java/net/imglib2/TwinCursor.java deleted file mode 100644 index ba18eb3..0000000 --- a/src/main/java/net/imglib2/TwinCursor.java +++ /dev/null @@ -1,173 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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.imglib2; - -import net.imglib2.predicate.MaskPredicate; -import net.imglib2.predicate.Predicate; -import net.imglib2.type.Type; -import net.imglib2.type.logic.BitType; - -/** - * The TwinCursor moves over two images with respect to a mask. The mask - * has to be of the same dimensionality as the images. Position information - * obtained from this class comes from the mask. - * - * @author Johannes Schindelin and Tom Kazimiers - */ -public class TwinCursor> implements Cursor, PairIterator { - final protected PredicateCursor mask; - final protected RandomAccess channel1; - final protected RandomAccess channel2; - /* - * For performance, we keep one position array (to avoid - * having to create a new array in every single step). - */ - final protected long[] position; - /* To avoid calling next() too often */ - protected boolean gotNext; - - public TwinCursor(final RandomAccess channel1, - final RandomAccess channel2, - final Cursor mask) { - final Predicate predicate = new MaskPredicate(); - this.mask = new PredicateCursor(mask, predicate); - this.channel1 = channel1; - this.channel2 = channel2; - position = new long[mask.numDimensions()]; - mask.localize(position); - } - - @Override - final public boolean hasNext() { - gotNext = false; - return mask.hasNext(); - } - - final public void getNext() { - if (gotNext) - return; - mask.next(); - mask.localize(position); - channel1.setPosition(position); - channel2.setPosition(position); - gotNext = true; - } - - @Override - final public T getFirst() { - getNext(); - return channel1.get(); - } - - @Override - final public T getSecond() { - getNext(); - return channel2.get(); - } - - @Override - public void reset() { - gotNext = false; - mask.reset(); - } - - @Override - public void fwd() { - if (hasNext()) - getNext(); - } - - @Override - public void jumpFwd(long arg0) { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - - @Override - public T next() { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - - @Override - public double getDoublePosition(int arg0) { - return mask.getDoublePosition(arg0); - } - - @Override - public float getFloatPosition(int arg0) { - return mask.getFloatPosition(arg0); - } - - @Override - public void localize(float[] arg0) { - mask.localize(arg0); - } - - @Override - public void localize(double[] arg0) { - mask.localize(arg0); - } - - @Override - public int numDimensions() { - return mask.numDimensions(); - } - - @Override - public Sampler copy() { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - - @Override - public T get() { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - - @Override - public int getIntPosition(int arg0) { - return mask.getIntPosition(arg0); - } - - @Override - public long getLongPosition(int arg0) { - return mask.getLongPosition(arg0); - } - - @Override - public void localize(int[] arg0) { - mask.localize(arg0); - } - - @Override - public void localize(long[] arg0) { - mask.localize(arg0); - } - - @Override - public Cursor copyCursor() { - throw new UnsupportedOperationException("This method has not been implemented, yet."); - } - } diff --git a/src/main/java/net/imglib2/algorithm/math/ImageStatistics.java b/src/main/java/net/imglib2/algorithm/math/ImageStatistics.java deleted file mode 100644 index b73a86b..0000000 --- a/src/main/java/net/imglib2/algorithm/math/ImageStatistics.java +++ /dev/null @@ -1,291 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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% - */ - -/* - * Copyright (c) 2009--2010, Stephan Preibisch & Stephan Saalfeld - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. Redistributions in binary - * form must reproduce the above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or other materials - * provided with the distribution. Neither the name of the Fiji project nor - * the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package net.imglib2.algorithm.math; - -import net.imglib2.Cursor; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.Type; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.util.RealSum; -import net.imglib2.view.Views; - -/** - * This class contains some basic image statistics - * calculations. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class ImageStatistics { - /** - * Calculates the number of pixels in the image. - * - * @param img The image to calculate the mean of - * @return The mean of the image passed - */ - final public static > long getNumPixels( - final RandomAccessibleInterval img ) - { - long numPixels = 1; - for (int d=0; d> double getImageMean( - final RandomAccessibleInterval img, - final RandomAccessibleInterval mask ) - { - final RealSum sum = new RealSum(); - long numPixels = 0; - // create cursor to walk an image with respect to a mask - final TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).localizingCursor()); - while (cursor.hasNext()) { - sum.add(cursor.getFirst().getRealDouble()); - ++numPixels; - } - - return sum.getSum() / numPixels; - } - - /** - * Calculates the mean of an image. - * - * @param img The image to calculate the mean of - * @return The mean of the image passed - */ - final public static > double getImageMean( - final RandomAccessibleInterval img ) - { - // Count all values using the RealSum class. - // It prevents numerical instabilities when adding up millions of pixels - RealSum realSum = new RealSum(); - long count = 0; - - for ( final T type : Views.iterable(img) ) - { - realSum.add( type.getRealDouble() ); - ++count; - } - - return realSum.getSum() / count; - } - - /** - * Calculates the integral of the pixel values of an image. - * - * @param img The image to calculate the integral of - * @return The pixel values integral of the image passed - */ - final public static > double getImageIntegral( - final RandomAccessibleInterval img ) - { - final RealSum sum = new RealSum(); - - for ( final T type : Views.iterable(img) ) - sum.add( type.getRealDouble() ); - - return sum.getSum(); - } - - /** - * Calculates the integral of the pixel values of an image. - * - * @param img The image to calculate the integral of - * @return The pixel values integral of the image passed - */ - final public static > double getImageIntegral( - final RandomAccessibleInterval img, - final RandomAccessibleInterval mask ) - { - final RealSum sum = new RealSum(); - // create cursor to walk an image with respect to a mask - final TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).cursor()); - while (cursor.hasNext()) - sum.add( cursor.getFirst().getRealDouble() ); - - return sum.getSum(); - } - - /** - * Calculates the min of an image. - * - * @param img The image to calculate the min of - * @return The min of the image passed - */ - final public static & Comparable> T getImageMin( - final RandomAccessibleInterval img ) - { - final Cursor cursor = Views.iterable(img).cursor(); - cursor.fwd(); - // copy first element as current maximum - final T min = cursor.get().copy(); - - while ( cursor.hasNext() ) - { - cursor.fwd(); - - final T currValue = cursor.get(); - - if ( currValue.compareTo( min ) < 0 ) - min.set( currValue ); - } - - return min; - } - - /** - * Calculates the min of an image with respect to a mask. - * - * @param img The image to calculate the min of - * @param mask The mask to respect - * @return The min of the image passed - */ - final public static & Comparable> T getImageMin( - final RandomAccessibleInterval img, - final RandomAccessibleInterval mask ) - { - // create cursor to walk an image with respect to a mask - final TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).localizingCursor()); - // forward one step to get the first value - cursor.fwd(); - // copy first element as current minimum - final T min = cursor.getFirst().copy(); - - while ( cursor.hasNext() ) { - cursor.fwd(); - - final T currValue = cursor.getFirst(); - - if ( currValue.compareTo( min ) < 0 ) - min.set( currValue ); - } - - return min; - } - - /** - * Calculates the max of an image. - * - * @param img The image to calculate the max of - * @return The max of the image passed - */ - final public static & Comparable> T getImageMax( - final RandomAccessibleInterval img ) { - - final Cursor cursor = Views.iterable(img).localizingCursor(); - cursor.fwd(); - // copy first element as current maximum - final T max = cursor.get().copy(); - - while ( cursor.hasNext() ) - { - cursor.fwd(); - - final T currValue = cursor.get(); - - if ( currValue.compareTo( max ) > 0 ) - max.set( currValue ); - } - - return max; - } - /** - * Calculates the max of an image with respect to a mask. - * - * @param img The image to calculate the min of - * @param mask The mask to respect - * @return The min of the image passed - */ - final public static & Comparable> T getImageMax( - final RandomAccessibleInterval img, - final RandomAccessibleInterval mask ) - { - // create cursor to walk an image with respect to a mask - final TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).localizingCursor()); - // forward one step to get the first value - cursor.fwd(); - final T max = cursor.getFirst().copy(); - - while ( cursor.hasNext() ) { - cursor.fwd(); - - final T currValue = cursor.getFirst(); - - if ( currValue.compareTo( max ) > 0 ) - max.set( currValue ); - } - - return max; - } -} diff --git a/src/main/java/net/imglib2/predicate/MaskPredicate.java b/src/main/java/net/imglib2/predicate/MaskPredicate.java deleted file mode 100644 index 7f67875..0000000 --- a/src/main/java/net/imglib2/predicate/MaskPredicate.java +++ /dev/null @@ -1,33 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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.imglib2.predicate; - -import net.imglib2.Cursor; -import net.imglib2.type.logic.BitType; - -public class MaskPredicate implements Predicate { - - @Override - public boolean test(final Cursor cursor) { - return cursor.get().get(); - } -} diff --git a/src/main/java/net/imglib2/predicate/Predicate.java b/src/main/java/net/imglib2/predicate/Predicate.java deleted file mode 100644 index 1cad19d..0000000 --- a/src/main/java/net/imglib2/predicate/Predicate.java +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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.imglib2.predicate; - -import net.imglib2.Cursor; -import net.imglib2.type.Type; - -/** - * An interface to check a value against arbitrary conditions. - */ -public interface Predicate> { - - // evaluate a predicate check for a given value - boolean test(Cursor value); -} diff --git a/src/main/java/sc/fiji/coloc/ColocImgLibGadgets.java b/src/main/java/sc/fiji/coloc/ColocImgLibGadgets.java deleted file mode 100644 index e412a19..0000000 --- a/src/main/java/sc/fiji/coloc/ColocImgLibGadgets.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc; - -import ij.IJ; -import ij.ImagePlus; -import ij.plugin.PlugIn; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -import net.imglib2.Cursor; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.ImagePlusAdapter; -import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.type.NativeType; -import net.imglib2.type.numeric.RealType; - -public class ColocImgLibGadgets & NativeType> implements PlugIn { - - protected Img img1, img2; - - @Override - public void run(String arg) { - ImagePlus imp1 = IJ.openImage("/Users/dan/Documents/Dresden/ipf/colocPluginDesign/red.tif"); - img1 = ImagePlusAdapter.wrap(imp1); - ImagePlus imp2 = IJ.openImage("/Users/dan/Documents/Dresden/ipf/colocPluginDesign/green.tif"); - img2 = ImagePlusAdapter.wrap(imp2); - - double pearson = calculatePearson(); - - Img ranImg = generateRandomImageStack(img1, new int[] {2,2,1}); - } - - /** - * To randomize blockwise we enumerate the blocks, shuffle that list and - * write the data to their new position based on the shuffled list. - */ - protected Img generateRandomImageStack(Img img, int[] blockDimensions) { - int numberOfDimensions = Math.min(img.numDimensions(), blockDimensions.length); - int numberOfBlocks = 0; - long[] numberOfBlocksPerDimension = new long[numberOfDimensions]; - - for (int i = 0 ; i allTheBlocks = new ArrayList(numberOfBlocks); - for (int i = 0; i cursor = img.cursor(); - - // create factories for new image stack - //ContainerFactory containerFactory = new ImagePlusContainerFactory(); - ImgFactory imgFactory = new ArrayImgFactory(); - //new ImageFactory(cursor.getType(), containerFactory); - - // create a new stack for the random images - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - Img randomStack = imgFactory.create(dim, img.firstElement().createVariable()); - - // iterate over image data - while (cursor.hasNext()) { - cursor.fwd(); - T type = cursor.get(); - // type.getRealDouble(); - } - - return randomStack; - } - - protected double calculatePearson() { - Cursor cursor1 = img1.cursor(); - Cursor cursor2 = img2.cursor(); - - double mean1 = getImageMean(img1); - double mean2 = getImageMean(img2); - - // Do some rather simple performance testing - long startTime = System.currentTimeMillis(); - - double pearson = calculatePearson(cursor1, mean1, cursor2, mean2); - - // End performance testing - long finishTime = System.currentTimeMillis(); - long elapsed = finishTime - startTime; - - // print some output to IJ log - IJ.log("mean of ch1: " + mean1 + " " + "mean of ch2: " + mean2); - IJ.log("Pearson's Coefficient " + pearson); - IJ.log("That took: " + elapsed + " ms"); - - return pearson; - } - - protected double calculatePearson(Cursor cursor1, double mean1, Cursor cursor2, double mean2) { - double pearsonDenominator = 0; - double ch1diffSquaredSum = 0; - double ch2diffSquaredSum = 0; - while (cursor1.hasNext() && cursor2.hasNext()) { - cursor1.fwd(); - cursor2.fwd(); - T type1 = cursor1.get(); - double ch1diff = type1.getRealDouble() - mean1; - T type2 = cursor2.get(); - double ch2diff = type2.getRealDouble() - mean2; - pearsonDenominator += ch1diff*ch2diff; - ch1diffSquaredSum += (ch1diff*ch1diff); - ch2diffSquaredSum += (ch2diff*ch2diff); - } - double pearsonNumerator = Math.sqrt(ch1diffSquaredSum * ch2diffSquaredSum); - return pearsonDenominator / pearsonNumerator; - } - - protected double getImageMean(Img img) { - double sum = 0; - Cursor cursor = img.cursor(); - while (cursor.hasNext()) { - cursor.fwd(); - T type = cursor.get(); - sum += type.getRealDouble(); - } - return sum / ImageStatistics.getNumPixels(img); - } -} diff --git a/src/main/java/sc/fiji/coloc/Coloc_2.java b/src/main/java/sc/fiji/coloc/Coloc_2.java deleted file mode 100644 index 5ac8321..0000000 --- a/src/main/java/sc/fiji/coloc/Coloc_2.java +++ /dev/null @@ -1,864 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc; - -import ij.IJ; -import ij.ImagePlus; -import ij.Prefs; -import ij.WindowManager; -import ij.gui.GenericDialog; -import ij.gui.Roi; -import ij.gui.ShapeRoi; -import ij.plugin.PlugIn; -import ij.plugin.frame.RoiManager; -import ij.process.Blitter; -import ij.process.ImageProcessor; - -import java.awt.Checkbox; -import java.awt.Rectangle; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.imglib2.Cursor; -import net.imglib2.IterableInterval; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.img.ImagePlusAdapter; -import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.type.NativeType; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.algorithms.Algorithm; -import sc.fiji.coloc.algorithms.AutoThresholdRegression; -import sc.fiji.coloc.algorithms.AutoThresholdRegression.Implementation; -import sc.fiji.coloc.algorithms.CostesSignificanceTest; -import sc.fiji.coloc.algorithms.Histogram2D; -import sc.fiji.coloc.algorithms.InputCheck; -import sc.fiji.coloc.algorithms.KendallTauRankCorrelation; -import sc.fiji.coloc.algorithms.LiHistogram2D; -import sc.fiji.coloc.algorithms.LiICQ; -import sc.fiji.coloc.algorithms.MandersColocalization; -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.PearsonsCorrelation; -import sc.fiji.coloc.algorithms.SpearmanRankCorrelation; -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.AnalysisResults; -import sc.fiji.coloc.results.PDFWriter; -import sc.fiji.coloc.results.ResultHandler; -import sc.fiji.coloc.results.SingleWindowDisplay; -import sc.fiji.coloc.results.Warning; - -/** - * An ImageJ plugin which does pixel intensity correlation based colocalisation - * analysis on a pair of images, with optional Mask or ROI. - * - * @param - * @author Daniel J. White - * @author Tom Kazimiers - * @author Johannes Schindelin - */ -public class Coloc_2 & NativeType> implements PlugIn { - - // a small bounding box container - protected class BoundingBox { - - public long[] offset; - public long[] size; - - public BoundingBox(final long[] offset, final long[] size) { - this.offset = offset.clone(); - this.size = size.clone(); - } - } - - // a storage class for ROI information - protected class MaskInfo { - - BoundingBox roi; - public Img mask; - - // constructors - public MaskInfo(final BoundingBox roi, final Img mask) { - this.roi = roi; - this.mask = mask; - } - - public MaskInfo() {} - } - - // the storage key for Fiji preferences - protected final static String PREF_KEY = "Coloc_2."; - - // Allowed types of ROI configuration - protected enum RoiConfiguration { - None, Img1, Img2, Mask, RoiManager - } - - // the ROI configuration to use - protected RoiConfiguration roiConfig = RoiConfiguration.Img1; - - // A list of all ROIs/masks found - protected ArrayList masks = new ArrayList<>(); - - // A list of auto threshold implementations - protected String[] regressions = - new String[AutoThresholdRegression.Implementation.values().length]; - - // default indices of image, mask, ROI and regression choices - protected static int index1 = 0; - protected static int index2 = 1; - protected static int indexMask = 0; - protected static int indexRoi = 0; - protected static int indexRegr = 0; - - // the images to work on - protected Img img1, img2; - - // names of the images working on - protected String Ch1Name = ""; - protected String Ch2Name = ""; - - // the channels of the images to use - protected int img1Channel = 1, img2Channel = 1; - - /* The different algorithms this plug-in provides. - * If a reference is null it will not get run. - */ - protected PearsonsCorrelation pearsonsCorrelation; - protected LiHistogram2D liHistogramCh1; - protected LiHistogram2D liHistogramCh2; - protected LiICQ liICQ; - protected SpearmanRankCorrelation SpearmanRankCorrelation; - protected MandersColocalization mandersCorrelation; - protected KendallTauRankCorrelation kendallTau; - protected Histogram2D histogram2D; - protected CostesSignificanceTest costesSignificance; - // indicates if images should be printed in result - protected boolean displayImages; - - // indicates if a PDF should be saved automatically - protected boolean autoSavePdf; - - @Override - public void run(final String arg0) { - if (showDialog()) { - try { - for (final MaskInfo mi : masks) { - colocalise(img1, img2, mi.roi, mi.mask); - } - } - catch (final MissingPreconditionException e) { - IJ.handleException(e); - IJ.showMessage("An error occured, could not colocalize!"); - return; - } - } - } - - public boolean showDialog() { - // get IDs of open windows - final int[] windowList = WindowManager.getIDList(); - // if there are less than 2 windows open, cancel - if (windowList == null || windowList.length < 2) { - IJ.showMessage("At least 2 images must be open!"); - return false; - } - - /* create a new generic dialog for the - * display of various options. - */ - final GenericDialog gd = new GenericDialog("Coloc 2"); - - final String[] titles = new String[windowList.length]; - /* the masks and ROIs array needs three more entries than - * windows to contain "none", "ROI ch 1" and "ROI ch 2" - */ - final String[] roisAndMasks = new String[windowList.length + 4]; - roisAndMasks[0] = ""; - roisAndMasks[1] = "ROI(s) in channel 1"; - roisAndMasks[2] = "ROI(s) in channel 2"; - roisAndMasks[3] = "ROI Manager"; - - // go through all open images and add them to GUI - for (int i = 0; i < windowList.length; i++) { - final ImagePlus imp = WindowManager.getImage(windowList[i]); - if (imp != null) { - titles[i] = imp.getTitle(); - roisAndMasks[i + 4] = imp.getTitle(); - } - else { - titles[i] = ""; - } - } - - // find all available regression strategies - final Implementation[] regressionImplementations = - AutoThresholdRegression.Implementation.values(); - for (int i = 0; i < regressionImplementations.length; ++i) { - regressions[i] = regressionImplementations[i].toString(); - } - - // set up the users preferences - displayImages = Prefs.get(PREF_KEY + "displayImages", false); - autoSavePdf = Prefs.get(PREF_KEY + "autoSavePdf", true); - boolean displayShuffledCostes = Prefs.get(PREF_KEY + - "displayShuffledCostes", false); - boolean useLiCh1 = Prefs.get(PREF_KEY + "useLiCh1", true); - boolean useLiCh2 = Prefs.get(PREF_KEY + "useLiCh2", true); - boolean useLiICQ = Prefs.get(PREF_KEY + "useLiICQ", true); - boolean useSpearmanRank = Prefs.get(PREF_KEY + "useSpearmanRank", true); - boolean useManders = Prefs.get(PREF_KEY + "useManders", true); - boolean useKendallTau = Prefs.get(PREF_KEY + "useKendallTau", true); - boolean useScatterplot = Prefs.get(PREF_KEY + "useScatterplot", true); - boolean useCostes = Prefs.get(PREF_KEY + "useCostes", true); - int psf = (int) Prefs.get(PREF_KEY + "psf", 3); - int nrCostesRandomisations = (int) Prefs.get(PREF_KEY + - "nrCostesRandomisations", 10); - indexRegr = (int) Prefs.get(PREF_KEY + "regressionImplementation", 0); - - /* make sure the default indices are no bigger - * than the amount of images we have - */ - index1 = clip(index1, 0, titles.length); - index2 = clip(index2, 0, titles.length); - indexMask = clip(indexMask, 0, roisAndMasks.length - 1); - - gd.addChoice("Channel_1", titles, titles[index1]); - gd.addChoice("Channel_2", titles, titles[index2]); - gd.addChoice("ROI_or_mask", roisAndMasks, roisAndMasks[indexMask]); - // gd.addChoice("Use ROI", roiLabels, roiLabels[indexRoi]); - - gd.addChoice("Threshold_regression", regressions, regressions[indexRegr]); - - gd.addCheckbox("Show_Save_PDF_Dialog", autoSavePdf); - gd.addCheckbox("Display_Images_in_Result", displayImages); - gd.addCheckbox("Display_Shuffled_Images", displayShuffledCostes); - final Checkbox shuffleCb = (Checkbox) gd.getCheckboxes().lastElement(); - // Add algorithm options - gd.addMessage("Algorithms:"); - gd.addCheckbox("Li_Histogram_Channel_1", useLiCh1); - gd.addCheckbox("Li_Histogram_Channel_2", useLiCh2); - gd.addCheckbox("Li_ICQ", useLiICQ); - gd.addCheckbox("Spearman's_Rank_Correlation", useSpearmanRank); - gd.addCheckbox("Manders'_Correlation", useManders); - gd.addCheckbox("Kendall's_Tau_Rank_Correlation", useKendallTau); - gd.addCheckbox("2D_Instensity_Histogram", useScatterplot); - gd.addCheckbox("Costes'_Significance_Test", useCostes); - final Checkbox costesCb = (Checkbox) gd.getCheckboxes().lastElement(); - gd.addNumericField("PSF", psf, 1); - gd.addNumericField("Costes_randomisations", nrCostesRandomisations, 0); - - // disable shuffle checkbox if costes checkbox is set to "off" - shuffleCb.setEnabled(useCostes); - costesCb.addItemListener(new ItemListener() { - - @Override - public void itemStateChanged(final ItemEvent e) { - shuffleCb.setEnabled(costesCb.getState()); - } - }); - - // show the dialog, finally - gd.showDialog(); - // do nothing if dialog has been canceled - if (gd.wasCanceled()) return false; - - final ImagePlus gdImp1 = WindowManager.getImage(gd.getNextChoiceIndex() + 1); - final ImagePlus gdImp2 = WindowManager.getImage(gd.getNextChoiceIndex() + 1); - - int gdIndexMask = gd.getNextChoiceIndex(); - int gdIndexRegr = gd.getNextChoiceIndex(); - boolean gdAutoSavePdf = gd.getNextBoolean(); - boolean gdDisplayImages = gd.getNextBoolean(); - boolean gdDisplayShuffledCostes = gd.getNextBoolean(); - boolean gdUseLiCh1 = gd.getNextBoolean(); - boolean gdUseLiCh2 = gd.getNextBoolean(); - boolean gdUseLiICQ = gd.getNextBoolean(); - boolean gdUseSpearmanRank = gd.getNextBoolean(); - boolean gdUseManders = gd.getNextBoolean(); - boolean gdUseKendallTau = gd.getNextBoolean(); - boolean gdUseScatterplot = gd.getNextBoolean(); - boolean gdUseCostes = gd.getNextBoolean(); - int gdPsf = (int) gd.getNextNumber(); - int gdNrCostesRandomisations = (int) gd.getNextNumber(); - - // save user preferences - Prefs.set(PREF_KEY + "regressionImplementation", gdIndexRegr); - Prefs.set(PREF_KEY + "autoSavePdf", gdAutoSavePdf); - Prefs.set(PREF_KEY + "displayImages", gdDisplayImages); - Prefs.set(PREF_KEY + "displayShuffledCostes", gdDisplayShuffledCostes); - Prefs.set(PREF_KEY + "useLiCh1", gdUseLiCh1); - Prefs.set(PREF_KEY + "useLiCh2", gdUseLiCh2); - Prefs.set(PREF_KEY + "useLiICQ", gdUseLiICQ); - Prefs.set(PREF_KEY + "useSpearmanRank", gdUseSpearmanRank); - Prefs.set(PREF_KEY + "useManders", gdUseManders); - Prefs.set(PREF_KEY + "useKendallTau", gdUseKendallTau); - Prefs.set(PREF_KEY + "useScatterplot", gdUseScatterplot); - Prefs.set(PREF_KEY + "useCostes", gdUseCostes); - Prefs.set(PREF_KEY + "psf", gdPsf); - Prefs.set(PREF_KEY + "nrCostesRandomisations", gdNrCostesRandomisations); - - return initializeSettings(gdImp1, gdImp2, gdIndexMask, gdIndexRegr, gdAutoSavePdf, gdDisplayImages, - gdDisplayShuffledCostes, gdUseLiCh1, gdUseLiCh2, gdUseLiICQ, gdUseSpearmanRank, gdUseManders, - gdUseKendallTau, gdUseScatterplot, gdUseCostes, gdPsf, gdNrCostesRandomisations); - } - - /** Programmatically initializes the colocalisation settings to match the given values. */ - public boolean initializeSettings(ImagePlus imp1, ImagePlus imp2, int gdIndexMask, int gdIndexRegr, - boolean gdAutoSavePdf, boolean gdDisplayImages, boolean gdDisplayShuffledCostes, boolean gdUseLiCh1, - boolean gdUseLiCh2, boolean gdUseLiICQ, boolean gdUseSpearmanRank, boolean gdUseManders, - boolean gdUseKendallTau, boolean gdUseScatterplot, boolean gdUseCostes, int gdPsf, - int gdNrCostesRandomisations) - { - // get image names for output - Ch1Name = imp1.getTitle(); - Ch2Name = imp2.getTitle(); - - // make sure neither image is RGB type - if (imp1.getBitDepth() == 24 || imp2.getBitDepth() == 24) { - IJ.showMessage("You should not use RGB color images to measure colocalization. Provide each channel as a 8-bit or 16-bit image."); - return false; - } - - // make sure both images have the same bit-depth - if (imp1.getBitDepth() != imp2.getBitDepth()) { - IJ.showMessage("Both images must have the same bit-depth."); - return false; - } - - // get information about the mask/ROI to use - indexMask = gdIndexMask; - if (indexMask == 0) roiConfig = RoiConfiguration.None; - else if (indexMask == 1) roiConfig = RoiConfiguration.Img1; - else if (indexMask == 2) roiConfig = RoiConfiguration.Img2; - else if (indexMask == 3) roiConfig = RoiConfiguration.RoiManager; - else { - roiConfig = RoiConfiguration.Mask; - /* Make indexMask the reference to the mask image to use. - * To do this we reduce it by three for the first three - * entries in the combo box. - */ - indexMask = indexMask - 4; - } - - // save the ImgLib wrapped images as members - img1 = ImagePlusAdapter.wrap(imp1); - img2 = ImagePlusAdapter.wrap(imp2); - - /* check if we have a valid ROI for the selected configuration - * and if so, get the ROI's bounds. Alternatively, a mask can - * be selected (that is basically all, but a rectangle). - */ - if (roiConfig == RoiConfiguration.Img1 && hasValidRoi(imp1)) { - createMasksFromImage(imp1); - } - else if (roiConfig == RoiConfiguration.Img2 && hasValidRoi(imp2)) { - createMasksFromImage(imp2); - } - else if (roiConfig == RoiConfiguration.RoiManager) { - if (!createMasksFromRoiManager(imp1.getWidth(), imp1.getHeight())) - return false; - } - else if (roiConfig == RoiConfiguration.Mask) { - // get the image to be used as mask - final int[] windowList = WindowManager.getIDList(); - final ImagePlus maskImp = WindowManager.getImage(windowList[indexMask]); - final Img maskImg = ImagePlusAdapter. wrap(maskImp); - // get a valid mask info for the image - final MaskInfo mi = getBoundingBoxOfMask(maskImg); - masks.add(mi); - } - else { - /* if no ROI/mask is selected, just add an empty MaskInfo - * to colocalise both images without constraints. - */ - masks.add(new MaskInfo(null, null)); - } - - // get information about the mask/ROI to use - indexRegr = gdIndexRegr; - - // read out GUI data - autoSavePdf = gdAutoSavePdf; - displayImages = gdDisplayImages; - - // Parse algorithm options - pearsonsCorrelation = new PearsonsCorrelation<>( - PearsonsCorrelation.Implementation.Fast); - - if (gdUseLiCh1) liHistogramCh1 = new LiHistogram2D<>("Li - Ch1", true); - if (gdUseLiCh2) liHistogramCh2 = new LiHistogram2D<>("Li - Ch2", false); - if (gdUseLiICQ) liICQ = new LiICQ<>(); - if (gdUseSpearmanRank) { - SpearmanRankCorrelation = new SpearmanRankCorrelation<>(); - } - if (gdUseManders) mandersCorrelation = new MandersColocalization<>(); - if (gdUseKendallTau) kendallTau = new KendallTauRankCorrelation<>(); - if (gdUseScatterplot) histogram2D = new Histogram2D<>( - "2D intensity histogram"); - if (gdUseCostes) { - costesSignificance = new CostesSignificanceTest<>(pearsonsCorrelation, - gdPsf, gdNrCostesRandomisations, gdDisplayShuffledCostes); - } - - return true; - } - - /** - * Call this method to run a whole colocalisation configuration, all selected - * algorithms get run on the supplied images. You can specify the data further - * by supplying appropriate information in the mask structure. - *

- * NB: This method returns {@code void} for binary backwards compatibility - * with old code which might invoke it. If you want access to the - * {@link AnalysisResults} directly, call - * {@link #colocalise(Img, Img, Coloc_2.BoundingBox, Img, List)} with - * {@code null} for {@code extraHandlers}. - *

- * - * @param image1 - * @param image2 - * @param roi - * @param mask - * @throws MissingPreconditionException - */ - public void colocalise(final Img image1, final Img image2, - final BoundingBox roi, final Img mask) - throws MissingPreconditionException - { - colocalise(image1, image2, roi, mask, null); - } - - /** - * Call this method to run a whole colocalisation configuration, all selected - * algorithms get run on the supplied images. You can specify the data further - * by supplying appropriate information in the mask structure. - * - * @param image1 First image. - * @param image2 Second image. - * @param roi Region of interest to which analysis is confined. - * @param mask Mask to which analysis is confined. - * @param extraHandlers additional objects to be notified of analysis results. - * @return Data structure housing the results. - * @throws MissingPreconditionException - */ - public AnalysisResults colocalise(final Img image1, final Img image2, - final BoundingBox roi, final Img mask, - final List> extraHandlers) - throws MissingPreconditionException - { - // create a new container for the selected images and channels - DataContainer container; - if (mask != null) { - container = new DataContainer<>(image1, image2, img1Channel, img2Channel, - Ch1Name, Ch2Name, mask, roi.offset, roi.size); - } - else if (roi != null) { - // we have no mask, but a regular ROI in use - container = new DataContainer<>(image1, image2, img1Channel, img2Channel, - Ch1Name, Ch2Name, roi.offset, roi.size); - } - else { - // no mask and no ROI is present - container = new DataContainer<>(image1, image2, img1Channel, img2Channel, - Ch1Name, Ch2Name); - } - - // create a results handler - final List> listOfResultHandlers = - new ArrayList<>(); - final AnalysisResults analysisResults = new AnalysisResults<>(); - listOfResultHandlers.add(analysisResults); - final PDFWriter pdfWriter = new PDFWriter<>(container); - final boolean headless = Boolean.getBoolean("java.awt.headless"); - final SingleWindowDisplay swDisplay; - if (headless) swDisplay = null; - else { - swDisplay = new SingleWindowDisplay<>(container, pdfWriter); - listOfResultHandlers.add(swDisplay); - } - listOfResultHandlers.add(pdfWriter); - if (extraHandlers != null) listOfResultHandlers.addAll(extraHandlers); - // ResultHandler resultHandler = new EasyDisplay(container); - - // this contains the algorithms that will be run when the user clicks ok - final List> userSelectedJobs = new ArrayList<>(); - - // add some pre-processing jobs: - userSelectedJobs.add(container.setInputCheck(new InputCheck())); - userSelectedJobs.add(container.setAutoThreshold( - new AutoThresholdRegression<>(pearsonsCorrelation, - AutoThresholdRegression.Implementation.values()[indexRegr]))); - - // add user selected algorithms - addIfValid(pearsonsCorrelation, userSelectedJobs); - addIfValid(liHistogramCh1, userSelectedJobs); - addIfValid(liHistogramCh2, userSelectedJobs); - addIfValid(liICQ, userSelectedJobs); - addIfValid(SpearmanRankCorrelation, userSelectedJobs); - addIfValid(mandersCorrelation, userSelectedJobs); - addIfValid(kendallTau, userSelectedJobs); - addIfValid(histogram2D, userSelectedJobs); - addIfValid(costesSignificance, userSelectedJobs); - - // execute all algorithms - int count = 0; - final int jobs = userSelectedJobs.size(); - for (final Algorithm a : userSelectedJobs) { - try { - count++; - IJ.showStatus(count + "/" + jobs + ": Running " + a.getName()); - a.execute(container); - } - catch (final MissingPreconditionException e) { - for (final ResultHandler r : listOfResultHandlers) { - r.handleWarning(new Warning("Probem with input data", a.getName() + - ": " + e.getMessage())); - } - } - } - // clear status - IJ.showStatus(""); - - // let the algorithms feed their results to the handler - for (final Algorithm a : userSelectedJobs) { - for (final ResultHandler r : listOfResultHandlers) - a.processResults(r); - } - // if we have ROIs/masks, add them to results - if (displayImages) { - RandomAccessibleInterval channel1, channel2; - if (mask != null || roi != null) { - final long[] offset = container.getMaskBBOffset(); - final long[] size = container.getMaskBBSize(); - channel1 = createMaskImage(container.getSourceImage1(), // - container.getMask(), offset, size); - channel2 = createMaskImage(container.getSourceImage2(), // - container.getMask(), offset, size); - } - else { - channel1 = container.getSourceImage1(); - channel2 = container.getSourceImage2(); - } - channel1 = project(channel1); - channel2 = project(channel2); - - for (final ResultHandler r : listOfResultHandlers) { - r.handleImage(channel1, "Channel 1 (Max Projection)"); - r.handleImage(channel2, "Channel 2 (Max Projection)"); - } - } - if (swDisplay != null) { - // do the actual results processing - swDisplay.process(); - // add window to the IJ window manager - swDisplay.addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(final WindowEvent e) { - WindowManager.removeWindow(swDisplay); - swDisplay.dispose(); - // NB: For some reason, garbage collection of this bundle of objects - // does not occur when this window listener reference remains in - // place. As such, we explicitly unregister ourself here. - swDisplay.removeWindowListener(this); - } - }); - WindowManager.addWindow(swDisplay); - } - - // show PDF saving dialog if requested - if (autoSavePdf) pdfWriter.process(); - - return analysisResults; - } - - private RandomAccessibleInterval project( - final RandomAccessibleInterval image) - { - if (image.numDimensions() < 2) { - throw new IllegalArgumentException("Dimensionality too small: " + // - image.numDimensions()); - } - - final IterableInterval input = Views.iterable(image); - final T type = input.firstElement(); // e.g. unsigned 8-bit - final long xLen = image.dimension(0); - final long yLen = image.dimension(1); - - // initialize output image with minimum value of the pixel type - final long[] outputDims = { xLen, yLen }; - final Img output = new ArrayImgFactory().create(outputDims, type); - for (final T sample : output) { - sample.setReal(type.getMinValue()); - } - - // loop over the input image, performing the max projection - final Cursor inPos = input.localizingCursor(); - final RandomAccess outPos = output.randomAccess(); - while (inPos.hasNext()) { - final T inPix = inPos.next(); - final long xPos = inPos.getLongPosition(0); - final long yPos = inPos.getLongPosition(1); - outPos.setPosition(xPos, 0); - outPos.setPosition(yPos, 1); - final T outPix = outPos.get(); - if (outPix.compareTo(inPix) < 0) { - outPix.set(inPix); - } - } - return output; - } - - /** - * A method to get the bounding box from the data in the given image that is - * above zero. Those values are interpreted as a mask. It will return null if - * no mask information was found. - * - * @param mask The image to look for "on" values in - * @return a new MaskInfo object or null - */ - protected MaskInfo getBoundingBoxOfMask(final Img mask) { - final Cursor cursor = mask.localizingCursor(); - - final int numMaskDims = mask.numDimensions(); - // the "off type" of the mask - final T offType = mask.firstElement().createVariable(); - offType.setZero(); - // the corners of the bounding box - final long[][] minMax = new long[2][]; - // indicates if mask data has been found - boolean maskFound = false; - // a container for temporary position information - final long[] pos = new long[numMaskDims]; - // walk over the mask - while (cursor.hasNext()) { - cursor.fwd(); - final T data = cursor.get(); - // test if the current mask data represents on or off - if (data.compareTo(offType) > 0) { - // get current position - cursor.localize(pos); - if (!maskFound) { - // we found mask data, first time - maskFound = true; - // init min and max with the current position - minMax[0] = Arrays.copyOf(pos, numMaskDims); - minMax[1] = Arrays.copyOf(pos, numMaskDims); - } - else { - /* Is is at least second hit, compare if it - * has new "extreme" positions, i.e. does - * is make the BB bigger? - */ - for (int d = 0; d < numMaskDims; d++) { - if (pos[d] < minMax[0][d]) { - // is it smaller than min - minMax[0][d] = pos[d]; - } - else if (pos[d] > minMax[1][d]) { - // is it larger than max - minMax[1][d] = pos[d]; - } - } - } - } - } - if (!maskFound) return null; - - // calculate size - final long[] size = new long[numMaskDims]; - for (int d = 0; d < numMaskDims; d++) - size[d] = minMax[1][d] - minMax[0][d] + 1; - // create and add bounding box - final BoundingBox bb = new BoundingBox(minMax[0], size); - return new MaskInfo(bb, mask); - } - - /** - * Adds the provided Algorithm to the list if it is not null. - */ - protected void addIfValid(final Algorithm a, - final List> list) - { - if (a != null) list.add(a); - } - - /** - * Returns true if a custom ROI has been selected, i.e if the current ROI does - * not have the extent of the whole image. - * - * @return true if custom ROI selected, false otherwise - */ - protected boolean hasValidRoi(final ImagePlus imp) { - final Roi roi = imp.getRoi(); - if (roi == null) return false; - - final Rectangle theROI = roi.getBounds(); - - // if the ROI is the same size as the image (default ROI), return false - return (theROI.height != imp.getHeight() || theROI.width != imp.getWidth()); - } - - /** - * Clips a value to the specified bounds. - */ - protected static int clip(final int val, final int min, final int max) { - return Math.max(Math.min(val, max), min); - } - - /** - * This method checks if the given ImagePlus contains any masks or ROIs. If - * so, the appropriate date structures are created and filled. - */ - protected void createMasksFromImage(final ImagePlus imp) { - // get ROIs from current image in Fiji - final Roi[] impRois = split(imp.getRoi()); - // create the ROIs - createMasksAndRois(impRois, imp.getWidth(), imp.getHeight()); - } - - /** - * A method to fill the masks array with data based on the ROI manager. - */ - protected boolean createMasksFromRoiManager(final int width, - final int height) - { - final RoiManager roiManager = RoiManager.getInstance(); - if (roiManager == null) { - IJ.error("Could not get ROI Manager instance."); - return false; - } - final Roi[] selectedRois = roiManager.getSelectedRoisAsArray(); - // create the ROIs - createMasksAndRois(selectedRois, width, height); - return true; - } - - /** - * Creates appropriate data structures from the ROI information - * passed. If an irregular ROI is found, it will be put into a - * frame of its bounding box size and put into an {@code Image}. - * - * In the end the members ROIs, masks and maskBBs will be - * filled if ROIs or masks were found. They will be null - * otherwise. - */ - protected void createMasksAndRois(final Roi[] rois, final int width, - final int height) - { - // create empty list - masks.clear(); - - for (final Roi r : rois) { - final MaskInfo mi = new MaskInfo(); - // add it to the list of masks/ROIs - masks.add(mi); - // get the ROIs/masks bounding box - final Rectangle rect = r.getBounds(); - mi.roi = new BoundingBox(new long[] { rect.x, rect.y }, new long[] { - rect.width, rect.height }); - final ImageProcessor ipMask = r.getMask(); - // check if we got a regular ROI and return if so - if (ipMask == null) { - continue; - } - - // create a mask processor of the same size as a slice - final ImageProcessor ipSlice = ipMask.createProcessor(width, height); - // fill the new slice with black - ipSlice.setValue(0.0); - ipSlice.fill(); - // position the mask on the new mask processor - ipSlice.copyBits(ipMask, (int) mi.roi.offset[0], (int) mi.roi.offset[1], - Blitter.COPY); - // create an Image out of it - final ImagePlus maskImp = new ImagePlus("Mask", ipSlice); - // and remember it and the masks bounding box - mi.mask = ImagePlusAdapter. wrap(maskImp); - } - } - - /** - * This method duplicates the given images, but respects ROIs if present. - * Meaning, a sub-picture will be created when source images are - * ROI/MaskImages. - * - * @throws MissingPreconditionException - */ - protected RandomAccessibleInterval createMaskImage( - final RandomAccessibleInterval image, - final RandomAccessibleInterval mask, final long[] offset, - final long[] size) throws MissingPreconditionException - { - final long[] pos = new long[image.numDimensions()]; - // sanity check - if (pos.length != offset.length || pos.length != size.length) { - throw new MissingPreconditionException( - "Mask offset and size must be of same dimensionality like image."); - } - // use twin cursor for only one image - final TwinCursor cursor = new TwinCursor<>(image.randomAccess(), // - image.randomAccess(), Views.iterable(mask).localizingCursor()); - // prepare output image - final ImgFactory maskFactory = new ArrayImgFactory<>(); - // Img maskImage = maskFactory.create( size, name ); - final RandomAccessibleInterval maskImage = maskFactory.create(size, // - image.randomAccess().get().createVariable()); - final RandomAccess maskCursor = maskImage.randomAccess(); - // go through the visible data and copy it to the output - while (cursor.hasNext()) { - cursor.fwd(); - cursor.localize(pos); - // shift coordinates by offset - for (int i = 0; i < pos.length; ++i) { - pos[i] = pos[i] - offset[i]; - } - // write out to correct position - maskCursor.setPosition(pos); - maskCursor.get().set(cursor.getFirst()); - } - - return maskImage; - } - - /** - * Splits a non overlapping composite ROI into its sub ROIs. - * - * @param roi The ROI to split - * @return A list of one or more ROIs - */ - public static Roi[] split(final Roi roi) { - if (roi instanceof ShapeRoi) return ((ShapeRoi) roi).getRois(); - return new Roi[] { roi }; - } -} diff --git a/src/main/java/sc/fiji/coloc/Colocalisation_Test.java b/src/main/java/sc/fiji/coloc/Colocalisation_Test.java deleted file mode 100644 index 7b46ed6..0000000 --- a/src/main/java/sc/fiji/coloc/Colocalisation_Test.java +++ /dev/null @@ -1,765 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc; - -//version 21 4 05 -//added van Steensel CCF analysis -//JCellSci v109.p787 -//version 29/4/05 -//Costes randomisation uses pixels in ch2 only once per random image - -import ij.IJ; -import ij.ImagePlus; -import ij.ImageStack; -import ij.Prefs; -import ij.WindowManager; -import ij.gui.GenericDialog; -import ij.gui.PlotWindow; -import ij.gui.Roi; -import ij.measure.Calibration; -import ij.plugin.PlugIn; -import ij.plugin.filter.GaussianBlur; -import ij.process.ByteProcessor; -import ij.process.ImageProcessor; -import ij.process.ImageStatistics; -import ij.process.ShortProcessor; -import ij.text.TextWindow; - -import java.awt.Rectangle; -import java.text.DecimalFormat; - -public class Colocalisation_Test implements PlugIn - {static boolean headingsSet2; - private static int index1=0; - private static int index2=1; - private ImagePlus imp1, imp2,impmask, imp3; - private ImageProcessor ipmask; - private int indexRoi= (int)Prefs.get("Rand_indexRoi.int",0); - private int indexRand= (int)Prefs.get("Rand_indexRand.int",0); - private boolean useROI, useMask ; - private Roi roi, roi1, roi2; - private static boolean randZ= Prefs.get("Rand_randZ.boolean", false); - private static boolean ignoreZeroZero= Prefs.get("Rand_ignore.boolean", true); - private static boolean smooth= Prefs.get("Rand_smooth.boolean", true); - private static boolean keep = Prefs.get("Rand_keep.boolean", false); - private static boolean currentSlice= Prefs.get("Rand_currentSlice.boolean", true); - private static boolean useManPSF= Prefs.get("Rand_useManPSF.boolean", false); - private static boolean showR= Prefs.get("Rand_showR.boolean", false); - private static double psf =0; - private static int manPSF= (int)Prefs.get("Rand_manPSF.int",10); - private static int iterations= (int)Prefs.get("Rand_iterations.int",0); - private static double ch2Lambda = Prefs.get("Rand_ch2L.double",520); - private static double NA = Prefs.get("Rand_NA.double",1.4); - private static double pixelSize = Prefs.get("Rand_pixelSize.double",0.10); - DecimalFormat df3 = new DecimalFormat("##0.000"); - DecimalFormat df2 = new DecimalFormat("##0.00"); - DecimalFormat df1 = new DecimalFormat("##0.0"); - DecimalFormat df0 = new DecimalFormat("##0"); - String[] chooseRand= { "Fay (x,y,z translation)","Costes approximation (smoothed noise)", "van Steensel (x translation)"}; - private int width, height, rwidth, rheight, xOffset, yOffset, mask; - String randMethod = "Fay"; - private long startTime; - private long endTime; - StringBuffer rVals = new StringBuffer(); - boolean Costes = false; - boolean Fay = false; - boolean vanS = false; - boolean rBlocks= false; - protected static TextWindow textWindow; - - @Override - public void run(String arg) - {startTime = System.currentTimeMillis(); - if (showDialog()) - correlate(imp1, imp2, imp3); - } - - public boolean showDialog() - { - int[] wList = WindowManager.getIDList(); - if (wList==null) - { - IJ.noImage(); - return false; - } - String[] titles = new String[wList.length]; - String[] chooseROI= new String[wList.length+3]; - chooseROI[0] = "None"; - chooseROI[1] = "ROI in channel 1 "; - chooseROI[2] = "ROI in channel 2"; - - if (indexRoi>wList.length+3) indexRoi=0; - for (int i=0; i=titles.length)index1 = 0; - if (index2>=titles.length)index2 = 0; - GenericDialog gd = new GenericDialog("Colocalisation Test"); - gd.addChoice("Channel_1", titles, titles[index1]); - gd.addChoice("Channel_2", titles, titles[index2]); - gd.addChoice("ROI or Mask", chooseROI, chooseROI[indexRoi]); - gd.addChoice("Randomization method", chooseRand,chooseRand[indexRand]); - //gd.addCheckbox("Ignore zero-zero pixels", ignoreZeroZero); - gd.addCheckbox("Current_slice only (Ch1)", currentSlice); - gd.addCheckbox("Keep_example randomized image", keep); - - gd.addCheckbox("Show_all_R_values from Ch1 vs Ch2(rand)", showR); - gd.addMessage("See: http://uhnresearch.ca/wcif/imagej"); - gd.showDialog(); - if (gd.wasCanceled()) return false; - index1 = gd.getNextChoiceIndex(); - index2 = gd.getNextChoiceIndex(); - indexRoi = gd.getNextChoiceIndex(); - indexRand=gd.getNextChoiceIndex(); - ignoreZeroZero = true; - currentSlice= gd.getNextBoolean(); - keep = gd.getNextBoolean(); - - showR=gd.getNextBoolean(); - String title1 = titles[index1]; - String title2 = titles[index2]; - imp1 = WindowManager.getImage(wList[index1]); - imp2 = WindowManager.getImage(wList[index2]); - - if (imp1.getType()==imp1.COLOR_RGB || imp2.getType()==imp1.COLOR_RGB) - { - IJ.showMessage("Colocalisation Test", "Both images must be grayscale."); - return false; - } - useMask=false; - if (indexRoi >=3) - { - imp3 = WindowManager.getImage(indexRoi-2); - useMask=true; - } - else imp3 = WindowManager.getImage(wList[index2]); - - Calibration cal = imp2.getCalibration(); - pixelSize = cal.pixelWidth; - - if(indexRand==0) - {Fay=true; - randMethod = "Fay"; - } - if(indexRand==1) - {Costes = true; - randMethod = "Costes X, Y"; - } - - if(indexRand==2) - {vanS=true; - randMethod = "van Steensel"; - } - - - -//test to ensure all images match up. - boolean matchWidth=false; - boolean matchHeight=false; - boolean matchSlice = false; - if (imp1.getWidth()==imp2.getWidth()&&imp1.getWidth()==imp3.getWidth()) matchWidth = true; - if (imp1.getHeight()==imp2.getHeight()&&imp1.getHeight()==imp3.getHeight()) matchHeight = true; - if (imp1.getStackSize()==imp2.getStackSize()&&imp1.getStackSize()==imp3.getStackSize()) matchSlice = true; - - if (!(matchWidth&&matchHeight&&matchSlice)) - {IJ.showMessage("Image mismatch","Images do not match. Exiting"); - return false; - } - - if (Costes||rBlocks) - { - GenericDialog gd2 = new GenericDialog("PSF details"); - gd2.addCheckbox("Randomize pixels in z-axis", randZ); - gd2.addNumericField("Pixel Size (µm)", pixelSize,3); - gd2.addNumericField("Channel_2_wavelength (nm)", ch2Lambda,0); - gd2.addNumericField("NA of objective", NA,2); - gd2.addNumericField("Iterations",iterations,0); - gd2.addMessage(""); - gd2.addCheckbox("Use_manual_PSF", useManPSF); - gd2.addNumericField("PSF_radius in pixels", manPSF, 0); - gd2.showDialog(); - if (gd2.wasCanceled()) return false; - randZ = gd2.getNextBoolean(); - if (randZ) randMethod+=", Z"; - pixelSize =gd2.getNextNumber(); - ch2Lambda = gd2.getNextNumber(); - NA = gd2.getNextNumber(); - iterations = (int)gd2.getNextNumber(); - useManPSF = gd2.getNextBoolean(); - manPSF = (int)gd2.getNextNumber(); - psf = (0.61*ch2Lambda)/NA; - psf = (psf)/(pixelSize*1000); - if (useManPSF) psf = manPSF; - //IJ.showMessage("PSF radius = "+df3.format(psf)); - } - return true; - } - - public void correlate(ImagePlus imp1, ImagePlus imp2, ImagePlus imp3) - { - String Ch1fileName = imp1.getTitle(); - String Ch2fileName = imp2.getTitle(); - ImageStack img1 = imp1.getStack(); - ImageStack img2 = imp2.getStack(); - ImageStack img3=imp3.getStack(); - int width = imp1.getWidth(); - int height = imp1.getHeight(); - String fileName = Ch1fileName + " and " + Ch2fileName; - ImageProcessor ip1 = imp1.getProcessor(); - ImageProcessor ip2 = imp2.getProcessor(); - ImageProcessor ip3= null; - if (useMask) ip3 = imp3.getProcessor(); - ImageStack stackRand = new ImageStack(rwidth,rheight); - ImageProcessor ipRand= img2.getProcessor(1); - int currentSliceNo = imp1.getCurrentSlice(); - if(currentSlice) fileName = fileName+ ". slice: "+currentSliceNo ; - double pearsons1 = 0; - double pearsons2 = 0; - double pearsons3 = 0; - double r2= 1; - double r=1; - double ch1Max=0; - double ch1Min = ip1.getMax(); - double ch2Max=0; - double ch2Min = ip1.getMax(); - int nslices = imp1.getStackSize(); - int ch1, ch2, count; - double sumX = 0; - double sumXY = 0; - double sumXX = 0; - double sumYY = 0; - double sumY = 0; - double sumXtotal=0; - double sumYtotal=0; - double colocX=0; - double colocY=0; - int N = 0; - int N2 = 0; - double r2min=1; - double r2max=-1; - sumX = 0; - sumXY = 0; - sumXX = 0; - sumYY = 0; - sumY = 0; - int i=1; - double coloc2M1 = 0; - double coloc2M2 = 0; - int colocCount=0; - int colocCount1=0; - int colocCount2=0; - double r2sd=0; - double sumr2sqrd=0; - double sumr2=0; - double ICQ2mean=0; - double sumICQ2sqrd=0; - double sumICQ2=0; - double ICQobs=0; - int countICQ=0; - int Nr=0; - int Ng=0; -//get stack2 histogram -ImageStatistics stats = imp2.getStatistics(); -if (imp2.getType() == imp2.GRAY16) - stats.nBins = 1<<16; -int [] histogram = new int[stats.nBins]; - - -//roi code - if (indexRoi==1||indexRoi==2) useROI = true; - else useROI=false; - - ip1 = imp1.getProcessor(); - ip2 = imp2.getProcessor(); - ip3 = imp2.getProcessor(); - if (useMask) ip3 = imp3.getProcessor(); - roi1 = imp1.getRoi(); - roi2 = imp2.getRoi(); - Rectangle rect =ip1.getRoi(); - if (indexRoi==1) - {if(roi1==null) useROI=false; - else - { - ipmask = imp1.getMask(); - rect = ip1.getRoi(); - } - } - if (indexRoi==2) - {if(roi2==null) useROI=false; - else{ipmask = imp2.getMask(); rect = ip2.getRoi();} - } - if (useROI==false) {xOffset = 0;yOffset = 0; rwidth=width; rheight =height;} - else {xOffset = rect.x; yOffset = rect.y; rwidth=rect.width; rheight =rect.height;} - - int g1=0;int g2=0; - int histCount=0; -//calulate pearsons for existing image; - for (int s=1; s<=nslices;s++) - {if (currentSlice) - {s=currentSliceNo; - nslices=s; - } - ip1 = img1.getProcessor(s); - ip2 = img2.getProcessor(s); - ip3 = img3.getProcessor(s); - for (int y=0; ych1) ch1Min = ch1; - if (ch2Maxch2) ch2Min = ch2; - N++; - if(ch1+ch2!=0) N2++; - sumXtotal += ch1; - sumYtotal += ch2; - if(ch2>0) colocX += ch1; - if(ch1>0) colocY += ch2; - sumX +=ch1; - sumXY += (ch1 * ch2); - sumXX += (ch1 * ch1); - sumYY += (ch2 *ch2); - sumY += ch2; - if(ch1>0) Nr++; - if(ch2>0)Ng++; - - //add ch2 value to histogram - histCount = histogram[ch2]; - histCount++; - histogram[ch2]=histCount; - - - } - } - } - } - - if (ignoreZeroZero) N = N2; - //N = N2; - //double ch1Mean = sumX/Nr; - //double ch2Mean = sumY/Ng; - double ch1Mean = sumX/N; - double ch2Mean = sumY/N; -// IJ.showMessage("Ch1: "+ch1Mean +" Ch2: "+ch2Mean +" count nonzerozero: "+N); - pearsons1 = sumXY - (sumX*sumY/N); - pearsons2 = sumXX - (sumX*sumX/N); - pearsons3 = sumYY - (sumY*sumY/N); - //IJ.showMessage("p1: "+pearsons1+" p2: "+pearsons2+" p3: "+pearsons3); - r= pearsons1/(Math.sqrt(pearsons2*pearsons3)); - double colocM1 = (double)(colocX/sumXtotal); - double colocM2 = (double)(colocY/sumYtotal); - -//calucalte ICQ - int countAll=0; - int countPos=0; - double PDMobs=0; - double PDM=0; - double ICQ2; - int countAll2=0; - - for (int s=1; s<=nslices;s++) - {if (currentSlice) - {s=currentSliceNo; - nslices=s; - } - ip1 = img1.getProcessor(s); - ip2 = img2.getProcessor(s); - ip3 = img3.getProcessor(s); - for (int y=0; y<=rheight; y++) - {IJ.showStatus("Calculating r for original images. Press 'Esc' to abort"); - if (IJ.escapePressed()) - {IJ.beep(); return;} - for (int x=0; x<=rwidth; x++) - {mask = (int)ip3.getPixelValue(x,y); - if (indexRoi==0) mask=1; - if((useROI)&&(ipmask!=null)) mask = (int)ipmask.getPixelValue(x,y); - - if (mask!=0) - { - ch1 = (int)ip1.getPixel(x+xOffset,y+yOffset); - ch2 = (int)ip2.getPixel(x+xOffset,y+yOffset); - if (ch1+ch2!=0) - { - PDMobs = ((double)ch1-(double)ch1Mean)*((double)ch2-(double)ch2Mean); - if (PDMobs>0) countPos++; - countAll2++; - } - - } - } - } - } - - //IJ.showMessage("count+ = "+countPos +" CountNonZeroPair= "+countAll2); - ICQobs = ((double)countPos/(double)countAll2)-0.5; - boolean ch3found= false; - //do random localisations - int rx=0; - int ry = 0; - int rz=0; - int ch3; - GaussianBlur gb = new GaussianBlur(); - double r2mean=0; - int slicesDone = 0; - int xCount=0; - int xOffset2 = -15; - int yOffset2 = -10; - int zOffset2=0; - int startSlice=1; - - if(Costes) - { - xOffset2=0; - yOffset2=0; - } - if (Fay) iterations = 25; - if (nslices>=2&&Fay) zOffset2=-1; - - if (Fay&&nslices>=2) - {startSlice=2; - nslices-=2; - iterations=75; - } - - if (vanS) - {xOffset2=-21; - startSlice=1; - iterations=41; - } - -int blockNumberX = (int)(width/(psf*2)); -int blockNumberY = (int)(height/(psf*2)); - -ImageProcessor blockIndex = new ByteProcessor(blockNumberX,blockNumberY); - -double [] vSx = new double [41]; -double [] vSr = new double [41] ; -int ch4=0; -int [] zUsed = new int [nslices]; -//stackRand = new ImageStack(rwidth,rheight); -int blockCount=0; -boolean rBlock=true; -int vacant; -//start randomisations and calculation or Rrands - for (int c=1; c<=iterations; c++) - { - stackRand = new ImageStack(rwidth,rheight); - if(Fay) - {if (c==26||c==51) - {zOffset2 += 1; - xOffset2=-15; - yOffset2=-10; - } - if (xOffset2<10) xOffset2+=5; - else {xOffset2 = -15; yOffset2+=5;} - } - if(vanS) - { - //IJ.showMessage("xOffset: "+xOffset2); - xOffset2+=1; - } - - - for (int s=startSlice; s<=nslices; s++) - { - ipRand = new ShortProcessor(rwidth,rheight); - slicesDone++; - if (currentSlice) - {s=currentSliceNo; - nslices=s; - } - IJ.showStatus("Iteration "+c+ "/"+iterations+" Slice: "+s +"/" +nslices+" 'Esc' to abort"); - if (IJ.escapePressed()) - {IJ.beep(); return;} - ip1= img1.getProcessor(s); - ip2 = img2.getProcessor(s+zOffset2); - ip3 = img3.getProcessor(s); - for (int y=0; y1)&&ch2!=0) - { - ch3 = (int)((Math.random()*(ch2Max-ch2Min))+ch2Min) ; - ipRand.putPixel(x,y,ch3); - } - - } - if (IJ.escapePressed()) - {IJ.beep(); return;} - //add to random image - - } - } - } - if (Costes) gb.blur(ipRand, psf); - stackRand.addSlice("Correlation Plot", ipRand); - } - //random image created now calculate r - - //reset values for r - sumXX=0; - sumX=0; - sumXY = 0; - sumYY = 0; - sumY = 0; - N = 0; - N2=0; - int s2=0; - sumXtotal = 0; - sumYtotal = 0; - colocX = 0; - colocY = 0; - double ICQrand=0; - int countPos2=0; - countAll=0; - //xOffset2=-21; - if (IJ.escapePressed()) - {IJ.beep(); return;} - for (int s=startSlice; s<=nslices;s++) - { - s2=s; - if (Fay&&nslices>=2) s2-=1; - if (currentSlice) - {s=currentSliceNo; - nslices=s; - s2=1; - } - ip1= img1.getProcessor(s); - ip2 = stackRand.getProcessor(s2); - for (int y=0; ych1) ch1Min = ch1; - if (ch2Maxch2) ch2Min = ch2; - N++; - //Mander calc - sumXtotal = sumXtotal+ch1; - sumYtotal = sumYtotal+ch2; - if(ch2>0) colocX = colocX + ch1; - if(ch1>0) colocY = colocY + ch2; - if((ch1+ch2!=0)) N2++; - sumX = sumX+ch1; - sumXY = sumXY + (ch1 * ch2); - sumXX = sumXX + (ch1 * ch1); - sumYY = sumYY + (ch2 *ch2); - sumY = sumY + ch2; - if (ch1+ch2!=0) - {PDM = ((double)ch1-(double)ch1Mean)*((double)ch2-(double)ch2Mean); - if (PDM>0) countPos2++; - countAll++; - } - } - } - } - } - if (ignoreZeroZero) N = N2; - ICQ2 = ((double)countPos2/(double)countAll)-0.5; - ICQ2mean+=ICQ2; - if (ICQobs>ICQ2) countICQ++; - pearsons1 = sumXY - (sumX*sumY/N); - pearsons2 = sumXX - (sumX*sumX/N); - pearsons3 = sumYY - (sumY*sumY/N); - r2= pearsons1/(Math.sqrt(pearsons2*pearsons3)); - - if(vanS) - { - vSx[c-1] = (double)xOffset2; - vSr[c-1] = (double)r2 ; - } - - if (r2r2max) r2max = r2; - //IJ.write("Random "+ c + "\t"+df3.format(r2)+ "\t"+ df3.format(coloc2M1) + "\t"+df3.format(coloc2M2)); - //IJ.write(df3.format(r2)); - rVals.append(r2+"\n"); - r2mean = r2mean+r2; - if (r>r2) colocCount++; - sumr2sqrd =sumr2sqrd +(r2*r2); - sumr2 = sumr2+r2; - sumICQ2sqrd +=(ICQ2*ICQ2); - sumICQ2 +=ICQ2; - //IJ.write(IJ.d2s(ICQ2,3)); - } -//done randomisations -//calcualte mean Rrand - r2mean = r2mean/iterations; - r2sd = Math.sqrt(((iterations*(sumr2sqrd))-(sumr2*sumr2))/(iterations*(iterations-1))); - ICQ2mean=ICQ2mean/iterations; - double ICQ2sd =Math.sqrt(((iterations*(sumICQ2sqrd))-(sumICQ2*sumICQ2))/(iterations*(iterations-1))); - double Zscore =(r-r2mean)/r2sd; - double ZscoreICQ = (ICQobs-ICQ2mean)/ICQ2sd; - String icqPercentile= "<50%"; - -String Percentile = ""+(iterations-colocCount)+"/"+iterations; - -//calculate percentage of Rrand that is less than Robs -//code from: -//http://www.cs.princeton.edu/introcs/26function/MyMath.java.html -//Thanks to Bob Dougherty -//50*{1 + erf[(V -mean)/(sqrt(2)*sdev)] - - double fx = 0.5*(1+erf(r-r2mean)/(Math.sqrt(2)*r2sd)); - if (fx>=1) fx=1; - if (fx<=0) fx=0; - String Percentile2 = IJ.d2s(fx,3)+""; - if(keep) new ImagePlus("Example random image", stackRand).show(); - double percColoc = ((double)colocCount/(double)iterations)*100; - double percICQ = ((double)countICQ/(double)iterations)*100; - String Headings2 = "Image" - +"\tR(obs)" - +"\tR(rand) mean±sd" - +"\tP-value" - +"\tR(rand)>R(obs)" - +"\tIterations" - +" \tRandomisation" - +"\tPSF width\n"; - - String strPSF = "na"; - if (Costes||rBlocks) strPSF = df3.format(psf*pixelSize*2)+ " µm ("+df0.format(psf*2)+" pix.)" ; - String str = fileName + - - "\t"+df3.format(r)+ - "\t" +df3.format(r2mean) + "±"+ df3.format(r2sd)+ - "\t"+Percentile2+ - "\t" + (Percentile )+ - "\t" +df0.format(iterations)+ - "\t" + randMethod+ - "\t" +strPSF; - if (textWindow == null) - textWindow = new TextWindow("Results", - Headings2, str, 400, 250); - else { - textWindow.getTextPanel().setColumnHeadings(Headings2); - textWindow.getTextPanel().appendLine(str); - } - - IJ.selectWindow("Results"); - if (showR) new TextWindow( "Random R values", "R(rand)", rVals.toString(),300, 400); - if(vanS) - {PlotWindow plot = new PlotWindow("CCF","x-translation","Pearsons",vSx,vSr); - //r2min = (1.05*r2min); - //r2max= (r2max*1.05); - //plot.setLimits(-20, 20, r2min, r2max); - plot.draw(); - } - Prefs.set("Rand_ignore.boolean", ignoreZeroZero); - Prefs.set("Rand_keep.boolean", keep); - Prefs.set("Rand_manPSF.int", manPSF); - Prefs.set("Rand_smooth.boolean", smooth); - if (Costes) Prefs.set("Rand_iterations.int", (int)iterations); - Prefs.set("Rand_ch2L.double",ch2Lambda); - Prefs.set("Rand_NA.double",NA); - Prefs.set("Rand_pixelSize.double",pixelSize); - Prefs.set("Rand_currentSlice.boolean", currentSlice); - Prefs.set("Rand_useManPSF.boolean", useManPSF); - Prefs.set("Rand_showR.boolean", showR); - Prefs.set("Rand_indexRoi.int",indexRoi); - Prefs.set("Rand_indexRand.int",indexRand); - Prefs.set("Rand_randZ.boolean",randZ); - long elapsedTime = (System.currentTimeMillis()-startTime)/1000; - String units = "secs"; - if (elapsedTime>90) - {elapsedTime /= 60; - units = "mins";} - IJ.showStatus("Done. "+ elapsedTime+ " "+ units); - } - -//code from: -//http://www.cs.princeton.edu/introcs/26function/MyMath.java.html - - public static double erf(double z) - { - double t = 1.0 / (1.0 + 0.5 * Math.abs(z)); - // use Horner's method - double ans = 1 - t * Math.exp( -z*z - 1.26551223 + - t * ( 1.00002368 + - t * ( 0.37409196 + - t * ( 0.09678418 + - t * (-0.18628806 + - t * ( 0.27886807 + - t * (-1.13520398 + - t * ( 1.48851587 + - t * (-0.82215223 + - t * ( 0.17087277)))))))))); - if (z >= 0) return ans; - else return -ans; - } -} - - diff --git a/src/main/java/sc/fiji/coloc/Colocalisation_Threshold.java b/src/main/java/sc/fiji/coloc/Colocalisation_Threshold.java deleted file mode 100644 index 1e44ca4..0000000 --- a/src/main/java/sc/fiji/coloc/Colocalisation_Threshold.java +++ /dev/null @@ -1,969 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc; - -//22/4/5 - -import ij.IJ; -import ij.ImagePlus; -import ij.ImageStack; -import ij.Prefs; -import ij.WindowManager; -import ij.gui.GenericDialog; -import ij.gui.Roi; -import ij.measure.Calibration; -import ij.plugin.PlugIn; -import ij.process.ColorProcessor; -import ij.process.FloatProcessor; -import ij.process.ImageConverter; -import ij.process.ImageProcessor; -import ij.process.ImageStatistics; -import ij.process.ShortProcessor; -import ij.text.TextWindow; - -import java.awt.Rectangle; -import java.text.DecimalFormat; - -public class Colocalisation_Threshold implements PlugIn { - boolean headingsSetCTC; - private static int index1=0; - private static int index2=1; - private static int indexMask; - private static boolean displayCounts; - private static boolean useMask; - private static boolean useRoi; - private ImagePlus imp1, imp2; - private static boolean threshold; - private int ch1, ch2, ch3, nslices, width, height; - private int indexRoi= (int)Prefs.get("CTC_indexRoi.int",0); - private DecimalFormat df4 = new DecimalFormat("##0.0000"); - private DecimalFormat df3 = new DecimalFormat("##0.000"); - private DecimalFormat df2 = new DecimalFormat("##0.00"); - private DecimalFormat df1 = new DecimalFormat("##0.0"); - private DecimalFormat df0 = new DecimalFormat("##0"); - private static boolean colocValConst= Prefs.get("CTC_colocConst.boolean", false); - private int dualChannelIndex = (int)Prefs.get("CTC_channels.int",0); - private static boolean bScatter= Prefs.get("CTC_bScatter.boolean", false); - private static boolean bShowLocalisation=Prefs.get("CTC_show.boolean", false); - boolean opt0 = Prefs.get("CTC_opt0.boolean", true); - boolean opt1 = Prefs.get("CTC_opt1.boolean", true); - boolean opt1a = Prefs.get("CTC_opt1a.boolean", true); - boolean opt2 = Prefs.get("CTC_opt2.boolean", true); - boolean opt3a = Prefs.get("CTC_opt3a.boolean", true); - boolean opt3b = Prefs.get("CTC_opt3b.boolean", true); - boolean opt4 = Prefs.get("CTC_opt4.boolean", true); - boolean opt5 = Prefs.get("CTC_opt5.boolean", true); - boolean opt6 = Prefs.get("CTC_opt6.boolean", true); - boolean opt7 = Prefs.get("CTC_opt7.boolean", true); - boolean opt8 = Prefs.get("CTC_opt8.boolean", true); - boolean opt9 = Prefs.get("CTC_opt9.boolean", true); - boolean opt10 = Prefs.get("CTC_opt10.boolean", true); - String[] dualChannels= { "Red : Green","Red : Blue", "Green : Blue",}; - private int colIndex1 = 0; - private int colIndex2 = 1; - private int colIndex3 = 2; - ImageProcessor ip1, ip2, ipmask; - ColorProcessor ipColoc; - ImagePlus colocPix; - - private int rwidth, rheight, xOffset, yOffset; - String[] chooseROI= { "None","Channel 1", "Channel 2",}; - protected static TextWindow textWindow; - - @Override - public void run(String arg) { - if (showDialog()) - correlate(imp1, imp2); - } - - public boolean showDialog() { - int[] wList = WindowManager.getIDList(); - if (wList==null) { - IJ.noImage(); - return false; - } - String[] titles = new String[wList.length]; - String[] chooseMask= new String[wList.length+1]; - chooseMask[0]=""; - - for (int i=0; i=titles.length)index1 = 0; - if (index2>=titles.length)index2 = 0; - if (indexMask>=titles.length)indexMask = 0; - - displayCounts = false; - threshold = false; - GenericDialog gd = new GenericDialog("Colocalisation Thresholds"); - gd.addChoice("Channel_1", titles, titles[index1]); - gd.addChoice("Channel_2", titles, titles[index2]); - gd.addChoice("Use ROI", chooseROI, chooseROI[indexRoi]); - - // gd.addChoice("Mask channel", chooseMask, chooseMask[indexMask]); - gd.addChoice("Channel Combination", dualChannels, dualChannels[dualChannelIndex]); - gd.addCheckbox("Show Colocalized Pixel Map",bShowLocalisation); - gd.addCheckbox("Use constant intensity for colocalized pixels",colocValConst); - gd.addCheckbox("Show Scatter plot",bScatter); - gd.addCheckbox("Include zero-zero pixels in threshold calculation",opt0); - - gd.addCheckbox("Set options",false); - gd.addMessage("See: http://uhnresearch.ca/wcif/imagej"); - gd.showDialog(); - if (gd.wasCanceled()) return false; - index1 = gd.getNextChoiceIndex(); - index2 = gd.getNextChoiceIndex(); - indexRoi = gd.getNextChoiceIndex(); - // indexMask = gd.getNextChoiceIndex(); - //IJ.showMessage(""+indexMask); - dualChannelIndex = gd.getNextChoiceIndex(); - bShowLocalisation = gd.getNextBoolean(); - colocValConst = gd.getNextBoolean(); - bScatter= gd.getNextBoolean(); - opt0 =gd.getNextBoolean(); - boolean options=gd.getNextBoolean(); - - imp1 = WindowManager.getImage(wList[index1]); - imp2 = WindowManager.getImage(wList[index2]); - useMask=false; - //IJ.showMessage(""+indexMask); - - - imp1 = WindowManager.getImage(wList[index1]); - imp2 = WindowManager.getImage(wList[index2]); - - if (imp1.getType()!=ImagePlus.GRAY8&&imp1.getType()!=ImagePlus.GRAY16&&imp2.getType()!=ImagePlus.GRAY16 &&imp2.getType()!=ImagePlus.GRAY8) { - IJ.showMessage("Image Correlator", "Both images must be 8-bit or 16-bit grayscale."); - return false; - } - ip1 = imp1.getProcessor(); - ip2 = imp2.getProcessor(); - Roi roi1 = imp1.getRoi(); - Roi roi2= imp2.getRoi(); - - width = imp1.getWidth(); - height = imp1.getHeight(); - useRoi=true; - if (indexRoi== 0) useRoi = false; - Rectangle rect =ip1.getRoi(); - - //IJ.showMessage("index"+rect.width); - - if ((indexRoi==1)) { - if (roi1==null) { - useRoi=false; - } else { - if (roi1.getType()==Roi.RECTANGLE) { - IJ.showMessage("Does not work with rectangular ROIs"); - return false; - } - ipmask = imp1.getMask(); - //if (keepROIimage) new ImagePlus("Mask",ipmask).show(); - rect = ip1.getRoi(); - } - } - - if ((indexRoi==2)) { - if (roi2==null) { - useRoi=false; - } else { - if (roi2.getType()==Roi.RECTANGLE) { - IJ.showMessage("Does not work with rectangular ROIs"); - return false; - } - ipmask = imp2.getMask(); - //if (keepROIimage) new ImagePlus("Mask",ipmask).show(); - rect = ip2.getRoi(); - } - } - - if (indexRoi==0) { - xOffset = 0; - yOffset = 0; - rwidth=width; - rheight =height; - } else { - xOffset = rect.x; - yOffset = rect.y; - rwidth=rect.width; - rheight =rect.height; - - } - - //if red-blue - if (dualChannelIndex==1) { - colIndex2 = 2; - colIndex3=1; - }; - - //if blue-green - if (dualChannelIndex==2) { - colIndex1 = 1; - colIndex2 =2 ; - colIndex3=0; - } - - if (options) { - GenericDialog gd2 = new GenericDialog("Set Results Options"); - gd2.addMessage("See online manual for detailed description of these values"); - gd2.addCheckbox("Show linear regression solution",opt1a); - gd2.addCheckbox("Show thresholds",opt1); - gd2.addCheckbox("Pearson's for whole image",opt2); - gd2.addCheckbox("Pearson's for image above thresholds",opt3a); - gd2.addCheckbox("Pearson's for image below thresholds (should be ~0)",opt3b); - gd2.addCheckbox("Mander's original coefficients (threshold = 0)",opt4); - gd2.addCheckbox("Mander's using thresholds",opt5); - gd2.addCheckbox("Number of colocalized voxels",opt6); - gd2.addCheckbox("% Image volume colocalized",opt7); - gd2.addCheckbox("% Voxels colocalized",opt8); - gd2.addCheckbox("% Intensity colocalized",opt9); - gd2.addCheckbox("% Intensity above threshold colocalized",opt10); - gd2.showDialog(); - if (gd2.wasCanceled()) return false; - - - opt1=gd2.getNextBoolean(); - opt1a=gd2.getNextBoolean(); - opt2=gd2.getNextBoolean(); - opt3a=gd2.getNextBoolean(); - opt3b=gd2.getNextBoolean(); - opt4=gd2.getNextBoolean(); - opt5=gd2.getNextBoolean(); - opt6=gd2.getNextBoolean(); - opt7=gd2.getNextBoolean(); - opt8=gd2.getNextBoolean(); - opt9=gd2.getNextBoolean(); - opt10=gd2.getNextBoolean(); - headingsSetCTC = false; - } - //IJ.showMessage(""+indexMask); - return true; - } - - public void correlate(ImagePlus imp1, ImagePlus imp2) {//IJ.showMessage("mask? "+useMask); - String ch1fileName = imp1.getTitle(); - String ch2fileName = imp2.getTitle(); - //String maskName = impMask.getTitle(); - String fileName = ch1fileName + " & " + ch2fileName; - ImageProcessor ip1 = imp1.getProcessor(); - ImageProcessor ip2 = imp2.getProcessor(); - Calibration spatialCalibration = imp1.getCalibration(); - - ImageProcessor ipMask = imp1.getMask(); - if (indexRoi>1) ipMask = imp2.getMask(); - - // ImageStack imgMask = impMask.getStack(); - ImageStack img1 = imp1.getStack(); - ImageStack img2 = imp2.getStack(); - if (indexRoi== 0) useRoi = false; - Rectangle rect1 =ip1.getRoi(); - Rectangle rect2 =ip2.getRoi(); - - Roi roi1 = imp1.getRoi(); - Roi roi2= imp2.getRoi(); - - nslices = imp1.getStackSize(); - width = imp1.getWidth(); - height = imp1.getHeight(); - ipColoc = new ColorProcessor(rwidth,rheight); - ImageStack stackColoc = new ImageStack(rwidth,rheight); - MinMaxContainer minMax1 = getMinMax(ip1); - MinMaxContainer minMax2 = getMinMax(ip2); - double ch1threshmin=0; - double ch1threshmax=minMax1.max; - double ch2threshmin=0; - double ch2threshmax=minMax2.max; - double pearsons1 = 0; - double pearsons2 = 0; - double pearsons3 = 0; - double r = 1; - pearsons1 =0; - pearsons2 = 0; - pearsons3 = 0; - double r2= 1; - boolean thresholdFound=false; - boolean unsigned = true; - int count =0; - double sumX = 0; - double sumXY = 0; - double sumXX = 0; - double sumYY = 0; - double sumY = 0; - double colocX = 0; - double colocY = 0; - double countX = 0; - double countY = 0; - double sumXYm=0; - int Nch1=0,Nch2=0; - double oldMax=0; - int sumCh2gtT =0; - int sumCh1gtT =0; - int N = 0; - int N2 = 0; - int Nzero=0; - int Nch1gtT=0; - int Nch2gtT=0; - - double oldMax2=0; - int ch1Max=(int)minMax1.max; - int ch2Max=(int)minMax2.max; - int ch1Min = (int)minMax1.min; - int ch2Min = (int)minMax2.min; - int ch1ROIMax=0; - int ch2ROIMax=0; - - String Headings = "\t \t \t \t \t \t \t \n"; - ImageProcessor plot32 = new FloatProcessor(256, 256); - ImageProcessor plot16 = new ShortProcessor(256, 256); - int scaledXvalue =0; - int scaledYvalue=0; - if (ch1Max<255) ch1Max=255; - if (ch2Max<255) ch2Max=255; - double ch1Scaling = (double)255/(double)ch1Max; - double ch2Scaling = (double)255/(double)ch2Max; - - // scaling for both channels should be the same so the scatterplot is not squewed - double chScaling = 1; - if (ch1Scaling>ch2Scaling) chScaling = ch1Scaling; - else chScaling = ch2Scaling; - - boolean divByZero=false; - - StringBuffer sb= new StringBuffer(); - String str=""; - int i = imp1.getCurrentSlice(); - double bBest=0; - double mBest = 0; - double bestr2=1; - double ch1BestThresh=0; - double ch2BestThresh=0; - String mString; - //start regression - IJ.showStatus("1/4: Performing regression. Press 'Esc' to abort"); - int ch1Sum=0; - int ch2Sum=0; - int ch3Sum=0; - double ch1mch1MeanSqSum=0; - double ch2mch2MeanSqSum= 0; - double ch3mch3MeanSqSum= 0; - ImageProcessor ipPlot = new ShortProcessor (256,256); - int mask=0; - - if (indexRoi== 0) useRoi = false; - Rectangle rect =ip1.getRoi(); - - - if ((indexRoi==1)) { - if (roi1==null) { - useRoi=false; - } else { - if (roi1.getType()==Roi.RECTANGLE) { - IJ.showMessage("Does not work with rectangular ROIs"); - return; - } - ipMask = imp1.getMask(); - //if (keepROIimage) new ImagePlus("Mask",ipmask).show(); - rect = ip1.getRoi(); - } - } - - if ((indexRoi==2)) { - if (roi2==null) { - useRoi=false; - } else { - if (roi2.getType()==Roi.RECTANGLE) { - IJ.showMessage("Does not work with rectangular ROIs"); - return ; - } - ipMask = imp2.getMask(); - //if (keepROIimage) new ImagePlus("Mask",ipmask).show(); - rect = ip2.getRoi(); - } - } - if (useRoi==false) { - xOffset = 0; - yOffset = 0; - rwidth=width; - rheight =height; - } else { - xOffset = rect.x; - yOffset = rect.y; - rwidth=rect.width; - rheight =rect.height; - - } - //new ImagePlus("Mask",ipMask).show(); - - //get means - for (int s=1; s<=nslices; s++) { - if (IJ.escapePressed()) { - IJ.beep(); - return; - } - ip1 = img1.getProcessor(s); - ip2 = img2.getProcessor(s); - //ipMask = imgMask.getProcessor(s); - - for (int y=0; ych1ROIMax) ch1ROIMax=ch1; - if (ch2>ch2ROIMax) ch2ROIMax=ch2; - - ch3 = ch1+ch2; - ch1Sum+=ch1; - ch2Sum+=ch2; - ch3Sum+=ch3; - if (ch1+ch2!=0) N++; - } - } - } - } - double ch1Mean = ch1Sum/N; - double ch2Mean = ch2Sum/N; - double ch3Mean = ch3Sum/N; - N=0; - - // Do some rather simple performance testing - long startTime = System.currentTimeMillis(); - - //calulate variances - for (int s=1; s<=nslices; s++) { - if (IJ.escapePressed()) { - IJ.beep(); - return; - } - ip1 = img1.getProcessor(s); - ip2 = img2.getProcessor(s); - //ipMask = imgMask.getProcessor(s); - for (int y=0; yr2*r2)) { - ch1BestThresh=ch1threshmax; - bestr2=r2; - } - - //if our r is close to our level of tolerance then set threshold has been found - if ((r2-tolerance) )thresholdFound = true; - - //if we've reached ch1 =1 then we've exhausted posibilities - if (Math.round(ch1threshmax)==0) thresholdFound =true; - - oldMax= newMax; - //change threshold max - if (r2>=0) { - if ((r2>=r2Prev)&&(!divByZero)) newMax = newMax/2; - if ((r20) { - Nch1++; - mCh2coloc = mCh2coloc+ch2; - } - if (ch2>0) { - Nch2++; - mCh1coloc = mCh1coloc+ch1; - } - - if ((double)ch2>=ch2threshmax) { - Nch2gtT++; - sumCh2gtT = sumCh2gtT+ch2; - colocX=colocX+ch1; - } - if ((double)ch1>=ch1threshmax) { - Nch1gtT++; - sumCh1gtT = sumCh1gtT+ch1; - colocY=colocY+ch2; - } - if (((double)ch1>ch1threshmax)&&((double)ch2>ch2threshmax)) { - sumColocCh1 = sumColocCh1+ch1; - sumColocCh2 = sumColocCh2+ch2; - Ncoloc++; - - //calc pearsons - sumX = sumX+ch1; - sumXY = sumXY + (ch1 * ch2); - sumXX = sumXX + (ch1 * ch1); - sumYY = sumYY + (ch2 *ch2); - sumY = sumY + ch2; - } - } - } - } - } - - //IJ.showMessage("Totoal"+N+" N0:"+Nzero+" Nc :"+ Ncoloc); - pearsons1 = sumXY - (sumX*sumY/Ncoloc); - pearsons2 = sumXX - (sumX*sumX/Ncoloc); - pearsons3 = sumYY - (sumY*sumY/Ncoloc); - - //Pearsons for coloclaised volume - double Rcoloc= pearsons1/(Math.sqrt(pearsons2*pearsons3)); - - //Mander's original - //[i.e. E(ch1if ch2>0) ÷ E(ch1total)] - - double M1 = mCh1coloc /sumCh1total; - double M2 = mCh2coloc /sumCh2total; - - - //Manders using threshold - //[i.e. E(ch1 if ch2>ch2threshold) ÷ (Ech1total)] - double colocM1 = (double) colocX/(double)sumCh1total; - double colocM2 = (double) colocY/(double)sumCh2total; - - //as in Coste's paper - //[i.e. E(ch1>ch1threshold) ÷ E(ch1total)] - - double colocC1 = (double)sumCh1gtT/ (double)sumCh1total; - double colocC2 = (double)sumCh2gtT/(double)sumCh2total; - - - //Imaris percentage volume - double percVolCh1 = (double)Ncoloc/ (double)Nch1gtT; - double percVolCh2 = (double)Ncoloc/(double)Nch2gtT; - - double percTotCh1 = (double) sumColocCh1/ (double)sumCh1total; - double percTotCh2 = (double) sumColocCh2/ (double)sumCh2total; - - //Imaris percentage material - double percMatCh1 = (double) sumColocCh1/(double)sumCh1gtT; - double percMatCh2 = (double)sumColocCh2/(double)sumCh2gtT; - //IJ.showMessage("Totoal"+N+" N0:"+Nzero+" Nc :"+ Ncoloc); - - sb.append(fileName+"\n"); - - //if (!useMask) maskName = ""; - - str = fileName +"\t"+"ROI" + indexRoi+"\t"; - str += opt0 ? "incl.\t" : "excl.\t"; - - if (opt2) str+= df3.format(rTotal)+ "\t"; - if (opt1a) str+= df3.format(m)+ "\t "+df1.format(b)+ "\t"; - if (opt1) str+= IJ.d2s(ch1threshmax,0)+"\t"+IJ.d2s(ch2threshmax,0)+"\t"; - if (opt3a) str+= df4.format(Rcoloc) +"\t"; - if (opt3b) str+= df3.format(bestr2)+"\t"; - if (opt4) str+= df4.format(M1)+ "\t "+df4.format(M2)+"\t"; - if (opt5) str+= df4.format(colocM1)+ "\t"+df4.format(colocM2)+"\t"; - if (opt6) str+= Ncoloc+ "\t"; - if (opt7) str+= df2.format(((double)Ncoloc*(double)100)/((double)width*(double)height*(double)nslices))+"%\t"; - if (opt8) str+= df2.format(percVolCh1*100 )+ "%\t"; - if (opt8) str+= df2.format(percVolCh2*100 )+ "%\t"; - if (opt9) str+= df2.format(percTotCh1*100 )+ "%\t"; - if (opt9) str+= df2.format(percTotCh2*100 )+ "%\t"; - if (opt10) str+= df2.format(percMatCh1*100 )+ "%\t"; - if (opt10) str+= df2.format(percMatCh2*100 )+ "%\t"; - - String heading = "Images\tMask\tZeroZero\t"; - - if (opt2) heading += "Rtotal\t"; - if (opt1a) heading += "m\tb\t"; - if (opt1) heading += "Ch1 thresh\tCh2 thresh\t"; - if (opt3a) heading += "Rcoloc\t"; - if (opt3b) heading += "RcolocPixelsImageThresh1)&&((double)ch2>colocPixelsImageThresh2)) { - colocInt=255; - if (!colocValConst) { - colocInt = (int)Math.sqrt(ch1*ch2); - } - color[colIndex1 ]=(int)colocInt; - color[colIndex2 ]=(int)colocInt; - color[colIndex3 ]=(int)colocInt; - - ipColoc.putPixel(x,y,color ); - } - } - } - } - //IJ.showMessage(stackColoc.getWidth()+ " - " + ipColoc.getWidth()); - stackColocPix.addSlice("Colocalized Pixel Map Image", ipColoc); - } - return stackColocPix; - } - - private class MinMaxContainer { - - public double min; - public double max; - - public MinMaxContainer(double min, double max){ - this.min = min; - this.max = max; - } - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/Accumulator.java b/src/main/java/sc/fiji/coloc/algorithms/Accumulator.java deleted file mode 100644 index 66eb70d..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/Accumulator.java +++ /dev/null @@ -1,109 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import net.imglib2.TwinCursor; -import net.imglib2.type.numeric.RealType; - -/** - * A class allowing an easy accumulation of values visited by a - * TwinCursor. After instantiation the sum of channel one, - * channel two, products with them self and a product of both of - * them will be available. It additionally provides the possibility - * to subtract values from the data before the adding them to the - * sum. - * - * @author Johannes Schindelin and Tom Kazimiers - */ -public abstract class Accumulator> { - protected double x, y, xx, xy, yy; - protected int count; - - /** - * The two values x and y from each cursor iteration to get - * summed up as single values and their combinations. - */ - public Accumulator(final TwinCursor cursor) { - this(cursor, false, 0.0d, 0.0d); - } - - /** - * The two values (x - xDiff) and (y - yDiff) from each cursor - * iteration to get summed up as single values and their combinations. - */ - public Accumulator(final TwinCursor cursor, double xDiff, double yDiff) { - this(cursor, true, xDiff, yDiff); - } - - protected Accumulator(final TwinCursor cursor, boolean substract, double xDiff, double yDiff) { - while (cursor.hasNext()) { - cursor.fwd(); - - T type1 = cursor.getFirst(); - T type2 = cursor.getSecond(); - - if (!accept(type1, type2)) - continue; - - double value1 = type1.getRealDouble(); - double value2 = type2.getRealDouble(); - - if (substract) { - value1 -= xDiff; - value2 -= yDiff; - } - - x += value1; - y += value2; - xx += value1 * value1; - xy += value1 * value2; - yy += value2 * value2; - count++; - } - } - - public abstract boolean accept(T type1, T type2); - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public double getXX() { - return xx; - } - - public double getXY() { - return xy; - } - - public double getYY() { - return yy; - } - - public int getCount() { - return count; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/Algorithm.java b/src/main/java/sc/fiji/coloc/algorithms/Algorithm.java deleted file mode 100644 index 46ac322..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/Algorithm.java +++ /dev/null @@ -1,92 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import java.util.ArrayList; -import java.util.List; - -import net.imglib2.type.numeric.RealType; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.ResultHandler; -import sc.fiji.coloc.results.Warning; - -/** - * An algorithm is an abstraction of techniques like the - * calculation of the Persons coefficient or Li'S ICQ. It - * allows to separate initialization and execution of - * such an algorithm. - */ -public abstract class Algorithm> { - // a name for the algorithm - protected String name; - /* a list of warnings that can be filled by the - * execute method - */ - List warnings = new ArrayList(); - - public Algorithm(String name) { - this.name = name; - } - - /** - * Executes the previously initialized {@link Algorithm}. - */ - public abstract void execute(DataContainer container) throws MissingPreconditionException; - - public String getName() { - return name; - } - - /** - * A method to give the algorithm the opportunity to let - * its results being processed by the passed handler. - * By default this methods passes the collected warnings to - * the handler and sub-classes should make use of this by - * adding custom behavior and call the super class. - * - * @param handler The ResultHandler to process the results. - */ - public void processResults(ResultHandler handler) { - for (Warning w : warnings) - handler.handleWarning( w ); - } - - /** - * Gets a reference to the warnings. - * - * @return A reference to the warnings list - */ - public List getWarnings() { - return warnings; - } - - /** - * Adds a warning to the list of warnings. - * - * @param shortMsg A short descriptive message - * @param longMsg A long message - */ - protected void addWarning(String shortMsg, String longMsg) { - warnings.add( new Warning(shortMsg, longMsg) ); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/AutoThresholdRegression.java b/src/main/java/sc/fiji/coloc/algorithms/AutoThresholdRegression.java deleted file mode 100644 index b91b356..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/AutoThresholdRegression.java +++ /dev/null @@ -1,349 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.ThresholdMode; -import sc.fiji.coloc.results.ResultHandler; - -/** - * A class implementing the automatic finding of a threshold - * used for Pearson colocalisation calculation. - */ -public class AutoThresholdRegression> extends Algorithm { - // Identifiers for choosing which implementation to use - public enum Implementation {Costes, Bisection}; - Implementation implementation = Implementation.Bisection; - /* The threshold for ratio of y-intercept : y-mean to raise a warning about - * it being to high or low, meaning far from zero. Don't use y-max as before, - * since this could be a very high value outlier. Mean is probably more - * reliable. - */ - final double warnYInterceptToYMeanRatioThreshold = 0.01; - // the slope and and intercept of the regression line - double autoThresholdSlope = 0.0, autoThresholdIntercept = 0.0; - /* The thresholds for both image channels. Pixels below a lower - * threshold do NOT include the threshold and pixels above an upper - * one will NOT either. Pixels "in between (and including)" thresholds - * do include the threshold values. - */ - T ch1MinThreshold, ch1MaxThreshold, ch2MinThreshold, ch2MaxThreshold; - // additional information - double bToYMeanRatio = 0.0; - //This is the Pearson's correlation we will use for further calculations - PearsonsCorrelation pearsonsCorrellation; - - public AutoThresholdRegression(PearsonsCorrelation pc) { - this(pc, Implementation.Costes); - } - - public AutoThresholdRegression(PearsonsCorrelation pc, Implementation impl) { - super("auto threshold regression"); - pearsonsCorrellation = pc; - implementation = impl; - } - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - // get the 2 images for the calculation of Pearson's - final RandomAccessibleInterval img1 = container.getSourceImage1(); - final RandomAccessibleInterval img2 = container.getSourceImage2(); - final RandomAccessibleInterval mask = container.getMask(); - - double ch1Mean = container.getMeanCh1(); - double ch2Mean = container.getMeanCh2(); - - double combinedMean = ch1Mean + ch2Mean; - - // get the cursors for iterating through pixels in images - TwinCursor cursor = new TwinCursor( - img1.randomAccess(), img2.randomAccess(), - Views.iterable(mask).localizingCursor()); - - // variables for summing up the - double ch1MeanDiffSum = 0.0, ch2MeanDiffSum = 0.0, combinedMeanDiffSum = 0.0; - double combinedSum = 0.0; - int N = 0, NZero = 0; - - // reference image data type - final T type = cursor.getFirst(); - - while (cursor.hasNext()) { - cursor.fwd(); - double ch1 = cursor.getFirst().getRealDouble(); - double ch2 = cursor.getSecond().getRealDouble(); - - combinedSum = ch1 + ch2; - - // TODO: Shouldn't the whole calculation take only pixels - // into account that are combined above zero? And not just - // the denominator (like it is done now)? - - // calculate the numerators for the variances - ch1MeanDiffSum += (ch1 - ch1Mean) * (ch1 - ch1Mean); - ch2MeanDiffSum += (ch2 - ch2Mean) * (ch2 - ch2Mean); - combinedMeanDiffSum += (combinedSum - combinedMean) * (combinedSum - combinedMean); - - // count only pixels that are above zero - if ( (ch1 + ch2) > 0.00001) - NZero++; - - N++; - } - - double ch1Variance = ch1MeanDiffSum / (N - 1); - double ch2Variance = ch2MeanDiffSum / (N - 1); - double combinedVariance = combinedMeanDiffSum / (N - 1.0); - - //http://mathworld.wolfram.com/Covariance.html - //?2 = X2?(X)2 - // = E[X2]?(E[X])2 - //var (x+y) = var(x)+var(y)+2(covar(x,y)); - //2(covar(x,y)) = var(x+y) - var(x)-var(y); - - double ch1ch2Covariance = 0.5*(combinedVariance - (ch1Variance + ch2Variance)); - - // calculate regression parameters - double denom = 2*ch1ch2Covariance; - double num = ch2Variance - ch1Variance - + Math.sqrt( (ch2Variance - ch1Variance) * (ch2Variance - ch1Variance) - + (4 * ch1ch2Covariance *ch1ch2Covariance) ); - - final double m = num/denom; - final double b = ch2Mean - m*ch1Mean ; - - // A stepper that walks thresholds - Stepper stepper; - // to map working thresholds to channels - ChannelMapper mapper; - - // let working threshold walk on channel one if the regression line - // leans more towards the abscissa (which represents channel one) for - // positive and negative correlation. - if (m > -1 && m < 1.0) { - // Map working threshold to channel one (because channel one has a - // larger maximum value. - mapper = new ChannelMapper() { - - @Override - public double getCh1Threshold(double t) { - return t; - } - - @Override - public double getCh2Threshold(double t) { - return (t * m) + b; - } - }; - // Select a stepper - if (implementation == Implementation.Bisection) { - // Start at the midpoint of channel one - stepper = new BisectionStepper( - Math.abs(container.getMaxCh1() + container.getMinCh1()) * 0.5, - container.getMaxCh1()); - } else { - stepper = new SimpleStepper(container.getMaxCh1()); - } - - } else { - // Map working threshold to channel two (because channel two has a - // larger maximum value. - mapper = new ChannelMapper() { - - @Override - public double getCh1Threshold(double t) { - return (t - b) / m; - } - - @Override - public double getCh2Threshold(double t) { - return t; - } - }; - // Select a stepper - if (implementation == Implementation.Bisection) { - // Start at the midpoint of channel two - stepper = new BisectionStepper( - Math.abs(container.getMaxCh2() + container.getMinCh2()) * 0.5, - container.getMaxCh2()); - } else { - stepper = new SimpleStepper(container.getMaxCh2()); - } - } - - // Min threshold not yet implemented - double ch1ThreshMax = container.getMaxCh1(); - double ch2ThreshMax = container.getMaxCh2(); - - // define some image type specific threshold variables - T thresholdCh1 = type.createVariable(); - T thresholdCh2 = type.createVariable(); - // reset the previously created cursor - cursor.reset(); - - /* Get min and max value of image data type. Since type of image - * one and two are the same, we dont't need to distinguish them. - */ - T dummyT = type.createVariable(); - final double minVal = dummyT.getMinValue(); - final double maxVal = dummyT.getMaxValue(); - - // do regression - while (!stepper.isFinished()) { - // round ch1 threshold and compute ch2 threshold - ch1ThreshMax = Math.round(mapper.getCh1Threshold(stepper.getValue())); - ch2ThreshMax = Math.round(mapper.getCh2Threshold(stepper.getValue())); - /* Make sure we don't get overflow the image type specific threshold variables - * if the image data type doesn't support this value. - */ - thresholdCh1.setReal(clamp(ch1ThreshMax, minVal, maxVal)); - thresholdCh2.setReal(clamp(ch2ThreshMax, minVal, maxVal)); - - try { - // do persons calculation within the limits - final double currentPersonsR = - pearsonsCorrellation.calculatePearsons(cursor, - ch1Mean, ch2Mean, thresholdCh1, thresholdCh2, - ThresholdMode.Below); - stepper.update(currentPersonsR); - } catch (MissingPreconditionException e) { - /* the exception that could occur is due to numerical - * problems within the Pearsons calculation. */ - stepper.update(Double.NaN); - } - - // reset the cursor to reuse it - cursor.reset(); - } - - /* Store the new results. The lower thresholds are the types - * min value for now. For the max threshold we do a clipping - * to make it fit into the image type. - */ - ch1MinThreshold = type.createVariable(); - ch1MinThreshold.setReal(minVal); - - ch1MaxThreshold = type.createVariable(); - ch1MaxThreshold.setReal(clamp(ch1ThreshMax, minVal, maxVal)); - - ch2MinThreshold = type.createVariable(); - ch2MinThreshold.setReal(minVal); - - ch2MaxThreshold = type.createVariable(); - ch2MaxThreshold.setReal(clamp(ch2ThreshMax, minVal, maxVal)); - - autoThresholdSlope = m; - autoThresholdIntercept = b; - bToYMeanRatio = b / container.getMeanCh2(); - - // add warnings if values are not in tolerance range - if ( Math.abs(bToYMeanRatio) > warnYInterceptToYMeanRatioThreshold ) { - addWarning("y-intercept far from zero", - "The ratio of the y-intercept of the auto threshold regression " + - "line to the mean value of Channel 2 is high. This means the " + - "y-intercept is far from zero, implying a significant positive " + - "or negative zero offset in the image data intensities. Maybe " + - "you should use a ROI. Maybe do a background subtraction in " + - "both channels. Make sure you didn't clip off the low " + - "intensities to zero. This might not affect Pearson's " + - "correlation values very much, but might harm other results."); - } - - // add warning if threshold is above the image mean - if (ch1ThreshMax > ch1Mean) { - addWarning("Threshold of ch. 1 too high", - "Too few pixels are taken into account for above-threshold calculations. The threshold is above the channel's mean."); - } - if (ch2ThreshMax > ch2Mean) { - addWarning("Threshold of ch. 2 too high", - "Too few pixels are taken into account for above-threshold calculations. The threshold is above the channel's mean."); - } - - // add warnings if values are below lowest pixel value of images - if ( ch1ThreshMax < container.getMinCh1() || ch2ThreshMax < container.getMinCh2() ) { - String msg = "The auto threshold method could not find a positive " + - "threshold, so thresholded results are meaningless."; - msg += implementation == Implementation.Costes ? "" : " Maybe you should try classic thresholding."; - addWarning("thresholds too low", msg); - } - } - - /** - * Clamp a value to a min or max value. If the value is below min, min is - * returned. Accordingly, max is returned if the value is larger. If it is - * neither, the value itself is returned. - */ - public static double clamp(double val, double min, double max) { - return min > val ? min : max < val ? max : val; - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - - handler.handleValue( "m (slope)", autoThresholdSlope , 2 ); - handler.handleValue( "b (y-intercept)", autoThresholdIntercept, 2 ); - handler.handleValue( "b to y-mean ratio", bToYMeanRatio, 2 ); - handler.handleValue( "Ch1 Max Threshold", ch1MaxThreshold.getRealDouble(), 2); - handler.handleValue( "Ch2 Max Threshold", ch2MaxThreshold.getRealDouble(), 2); - handler.handleValue( "Threshold regression", implementation.toString()); - } - - public double getBToYMeanRatio() { - return bToYMeanRatio; - } - - public double getWarnYInterceptToYMaxRatioThreshold() { - return warnYInterceptToYMeanRatioThreshold; - } - - public double getAutoThresholdSlope() { - return autoThresholdSlope; - } - - public double getAutoThresholdIntercept() { - return autoThresholdIntercept; - } - - public T getCh1MinThreshold() { - return ch1MinThreshold; - } - - public T getCh1MaxThreshold() { - return ch1MaxThreshold; - } - - public T getCh2MinThreshold() { - return ch2MinThreshold; - } - - public T getCh2MaxThreshold() { - return ch2MaxThreshold; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/BisectionStepper.java b/src/main/java/sc/fiji/coloc/algorithms/BisectionStepper.java deleted file mode 100644 index de98904..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/BisectionStepper.java +++ /dev/null @@ -1,91 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * Try to converge a threshold based on an update value condition. If the - * update value is larger zero, the threshold is lowered by half the distance - * between the last thresholds. If the update value falls below zero or is not - * a number, the threshold is increased by such a half step. - * - * @author Tom Kazimiers - * - */ -public class BisectionStepper extends Stepper { - protected double threshold1; - protected double threshold2; - protected double thrDiff = Double.NaN; - protected int iterations = 0; - protected int maxIterations = 100; - - /** - * Initialize the bisection stepper with a start threshold and its - * last threshold - * - * @param threshold The current threshold - * @param lastThreshold The last threshold - */ - public BisectionStepper(double threshold, double lastThreshold) { - threshold1 = threshold; - threshold2 = lastThreshold; - thrDiff = Math.abs(threshold1 - threshold2); - } - - /** - * Update threshold by a bisection step. If {@code value} is below zero or - * not a number, the step is made upwards. If it is above zero, the stoep is - * downwards. - */ - @Override - public void update(double value) { - // update working thresholds for next iteration - threshold2 = threshold1; - if (Double.NaN == value || value < 0) { - // we went too far, increase by the absolute half - threshold1 = threshold1 + thrDiff * 0.5; - } else if (value > 0) { - // as long as r > 0 we go half the way down - threshold1 = threshold1 - thrDiff * 0.5; - } - // Update difference to last threshold - thrDiff = Math.abs(threshold1 - threshold2); - // Update update counter - iterations++; - } - - /** - * Get current threshold. - */ - @Override - public double getValue() { - return threshold1; - } - - /** - * If the difference between both thresholds is < 1, we consider - * that as reasonable close to abort the regression. - */ - @Override - public boolean isFinished() { - return iterations > maxIterations || thrDiff < 1.0; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/ChannelMapper.java b/src/main/java/sc/fiji/coloc/algorithms/ChannelMapper.java deleted file mode 100644 index 61d70af..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/ChannelMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * A channel mapper should map an input value to either channel one or - * channel two. - * - * @author Tom Kazimiers - */ -public interface ChannelMapper { - double getCh1Threshold(double t); - double getCh2Threshold(double t); -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/CostesSignificanceTest.java b/src/main/java/sc/fiji/coloc/algorithms/CostesSignificanceTest.java deleted file mode 100644 index f092315..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/CostesSignificanceTest.java +++ /dev/null @@ -1,421 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import net.imglib2.Cursor; -import net.imglib2.IterableInterval; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.gauss.Gauss; -import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.roi.RectangleRegionOfInterest; -import net.imglib2.type.NativeType; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.DataContainer.MaskType; -import sc.fiji.coloc.gadgets.Statistics; -import sc.fiji.coloc.results.ResultHandler; - -public class CostesSignificanceTest & NativeType> extends Algorithm { - // radius of the PSF in pixels, its size *must* for now be three - protected double[] psfRadius = new double[3]; - // indicates if the shuffled images should be shown as a result - boolean showShuffledImages = false; - // the number of randomization tests - int nrRandomizations; - // the shuffled image last worked on - Img smoothedShuffledImage; - // the Pearson's algorithm (that should have been run before) - PearsonsCorrelation pearsonsCorrelation; - // a list of resulting Pearsons values from the randomized images - List shuffledPearsonsResults; - /* the amount of Pearson's values with shuffled data - * that has the value of the original one or is larger. - */ - int shuffledPearsonsNotLessOriginal = 0; - // The mean of the shuffled Pearson values - double shuffledMean = 0.0; - // The standard derivation of the shuffled Pearson values - double shuffledStdDerivation = 0.0; - /* The Costes P-Value which is the probability that - * Pearsons r is different from the mean of the randomized - * r values. - */ - double costesPValue; - // the maximum retries in case of Pearson numerical errors - protected final int maxErrorRetries = 3; - - - /** - * Creates a new Costes significance test object by using a - * cube block with the given edge length. - * - * @param psfRadiusInPixels The edge width of the 3D cube block. - */ - public CostesSignificanceTest(PearsonsCorrelation pc, int psfRadiusInPixels, - int nrRandomizations, boolean showShuffledImages) { - super("Costes significance test"); - this.pearsonsCorrelation = pc; - Arrays.fill(psfRadius, psfRadiusInPixels); - this.nrRandomizations = nrRandomizations; - this.showShuffledImages = showShuffledImages; - } - - /** - * Builds a list of blocks that represent the images. To - * do so we create a list image ROI cursors. If a block - * does not fit into the image it will get a out-of-bounds - * strategy. - */ - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - final RandomAccessibleInterval img1 = container.getSourceImage1(); - final RandomAccessibleInterval img2 = container.getSourceImage2(); - final RandomAccessibleInterval mask = container.getMask(); - - /* To determine the number of needed blocks, we need - * the effective dimensions of the image. Since the - * mask is responsible for this, we ask for its size. - */ - long[] dimensions = container.getMaskBBSize(); - int nrDimensions = dimensions.length; - - // calculate the needed number of blocks per image - int nrBlocksPerImage = 1; - long[] nrBlocksPerDimension = new long[3]; - for (int i = 0; i < nrDimensions; i++) { - // add the amount of full fitting blocks to the counter - nrBlocksPerDimension[i] = (long) (dimensions[i] / psfRadius[i]); - // if there is the need for a out-of-bounds block, increase count - if ( dimensions[i] % psfRadius[i] != 0 ) - nrBlocksPerDimension[i]++; - // increase total count - nrBlocksPerImage *= nrBlocksPerDimension[i]; - } - - /* For creating the input and output blocks we need - * offset and size as floating point array. - */ - double[] floatOffset = new double[ img1.numDimensions() ]; - long[] longOffset = container.getMaskBBOffset(); - for (int i=0; i< longOffset.length; ++i ) - floatOffset[i] = longOffset[i]; - double[] floatDimensions = new double[ nrDimensions ]; - for (int i=0; i< nrDimensions; ++i ) - floatDimensions[i] = dimensions[i]; - - /* Create the ROI blocks. The image dimensions might not be - * divided cleanly by the block size. Therefore we need to - * have an out of bounds strategy -- a mirror. - */ - List> blockIntervals; - blockIntervals = new ArrayList>( nrBlocksPerImage ); - RandomAccessible< T> infiniteImg = Views.extendMirrorSingle( img1 ); - generateBlocks( infiniteImg, blockIntervals, floatOffset, floatDimensions); - - // create input and output cursors and store them along their offset - List> inputBlocks = new ArrayList>(nrBlocksPerImage); - List> outputBlocks = new ArrayList>(nrBlocksPerImage); - for (IterableInterval roiIt : blockIntervals) { - inputBlocks.add(roiIt.localizingCursor()); - outputBlocks.add(roiIt.localizingCursor()); - } - - // we will need a zero variable - final T zero = img1.randomAccess().get().createVariable(); - zero.setZero(); - - /* Create a new image to contain the shuffled data and with - * same dimensions as the original data. - */ - final long[] dims = new long[img1.numDimensions()]; - img1.dimensions(dims); - ImgFactory factory = new ArrayImgFactory(); - Img shuffledImage = factory.create( - dims, img1.randomAccess().get().createVariable() ); - RandomAccessible< T> infiniteShuffledImage = - Views.extendValue(shuffledImage, zero ); - - // create a double version of the PSF for the smoothing - double[] smoothingPsfRadius = new double[nrDimensions]; - for (int i = 0; i < nrDimensions; i++) { - smoothingPsfRadius[i] = (double) psfRadius[i]; - } - - // the retry count for error cases - int retries = 0; - - shuffledPearsonsResults = new ArrayList(); - for (int i=0; i < nrRandomizations; i++) { - // shuffle the list - Collections.shuffle( inputBlocks ); - // get an output random access - RandomAccess output = infiniteShuffledImage.randomAccess(); - - // check if a mask is in use and further actions are needed - if (container.getMaskType() == MaskType.Irregular) { - Cursor siCursor = shuffledImage.cursor(); - // black the whole intermediate image, just in case we have irr. masks - while (siCursor.hasNext()) { - siCursor.fwd(); - output.setPosition(siCursor); - output.get().setZero(); - } - } - - // write out the shuffled input blocks into the output blocks - for (int j=0; j inputCursor = inputBlocks.get(j); - Cursor outputCursor = outputBlocks.get(j); - /* Iterate over both blocks. Theoretically the iteration - * order could be different. Because we are dealing with - * randomized data anyway, this is not a problem here. - */ - while (inputCursor.hasNext() && outputCursor.hasNext()) { - inputCursor.fwd(); - outputCursor.fwd(); - output.setPosition(outputCursor); - // write the data - output.get().set( inputCursor.get() ); - } - - /* Reset both cursors. If we wouldn't do that, the - * image contents would not change on the next pass. - */ - inputCursor.reset(); - outputCursor.reset(); - } - - smoothedShuffledImage = Gauss.inFloat( smoothingPsfRadius, shuffledImage); - - try { - // calculate correlation value... - double pValue = pearsonsCorrelation.calculatePearsons( smoothedShuffledImage, img2, mask); - // ...and add it to the results list - shuffledPearsonsResults.add( pValue ); - } catch (MissingPreconditionException e) { - /* if the randomized input data does not suit due to numerical - * problems, try it three times again and then fail. - */ - if (retries < maxErrorRetries) { - // increase retry count and the number of randomizations - retries++; - nrRandomizations++; - } else { - throw new MissingPreconditionException("Maximum retries have been made (" + - + retries + "), but errors keep on coming: " + e.getMessage(), e); - } - } - } - - // calculate statistics on the randomized values and the original one - double originalVal = pearsonsCorrelation.getPearsonsCorrelationValue(); - calculateStatistics(shuffledPearsonsResults, originalVal); - } - - /** - * This method drives the creation of RegionOfInterest-Cursors on the given image. - * It does not matter if those generated blocks are used for reading and/or - * writing. The resulting blocks are put into the given list and are in the - * responsibility of the caller, i.e. he or she must make sure the cursors get - * closed on some point in time. - * - * @param img The image to create cursors on. - * @param blockList The list to put newly created cursors into - * @param offset - * @param size - */ - protected void generateBlocks(RandomAccessible img, List> blockList, - double[] offset, double[] size) - throws MissingPreconditionException { - // get the number of dimensions - int nrDimensions = img.numDimensions(); - if (nrDimensions == 2) - { // for a 2D image... - generateBlocksXY(img, blockList, offset, size); - } - else if (nrDimensions == 3) - { // for a 3D image... - final double depth = size[2]; - double z; - double originalZ = offset[2]; - // go through the depth in steps of block depth - for ( z = psfRadius[2]; z <= depth; z += psfRadius[2] ) { - - offset[2] = originalZ + z - psfRadius[2]; - generateBlocksXY(img, blockList, offset, size); - } - // check is we need to add a out of bounds strategy cursor - if (z > depth) { - offset[2] = originalZ + z - psfRadius[2]; - generateBlocksXY(img, blockList, offset, size); - } - offset[2] = originalZ; - } - else - throw new MissingPreconditionException("Currently only 2D and 3D images are supported."); - } - - /** - * Goes stepwise through the y-dimensions of the image data and adds cursors - * for each row to the given list. The method does not check if there is a - * y-dimensions, so this should be made sure before. you can enforce to - * create all cursors as out-of-bounds one. - * - * @param img The image to get the data and cursors from. - * @param blockList The list to put the blocks into. - * @param offset The current offset configuration. Only [0] and [1] will be changed. - * @param size - */ - protected void generateBlocksXY(RandomAccessible img, List> blockList, - double[] offset, double[] size) { - // potentially masked image height - double height = size[1]; - final double originalY = offset[1]; - // go through the height in steps of block width - double y; - for ( y = psfRadius[1]; y <= height; y += psfRadius[1] ) { - offset[1] = originalY + y - psfRadius[1]; - generateBlocksX(img, blockList, offset, size); - } - // check is we need to add a out of bounds strategy cursor - if (y > height) { - offset[1] = originalY + y - psfRadius[1]; - generateBlocksX(img, blockList, offset, size); - } - offset[1] = originalY; - } - - /** - * Goes stepwise through a row of image data and adds cursors to the given list. - * If there is not enough image data for a whole block, an out-of-bounds cursor - * is generated. The creation of out-of-bound cursors could be enforced as well. - * - * @param img The image to get the data and cursors from. - * @param blockList The list to put the blocks into. - * @param offset The current offset configuration. Only [0] of it will be changed. - * @param size - */ - protected void generateBlocksX(RandomAccessible img, List> blockList, - double[] offset, double[] size) { - // potentially masked image width - double width = size[0]; - final double originalX = offset[0]; - // go through the width in steps of block width - double x; - for ( x = psfRadius[0]; x <= width; x += psfRadius[0] ) { - offset[0] = originalX + x - psfRadius[0]; - RectangleRegionOfInterest roi = - new RectangleRegionOfInterest(offset.clone(), psfRadius.clone()); - IterableInterval roiInterval = roi.getIterableIntervalOverROI(img); - blockList.add(roiInterval); - } - // check is we need to add a out of bounds strategy cursor - if (x > width) { - offset[0] = originalX + x - psfRadius[0]; - RectangleRegionOfInterest roi = - new RectangleRegionOfInterest(offset.clone(), psfRadius.clone()); - IterableInterval roiInterval = roi.getIterableIntervalOverROI(img); - blockList.add(roiInterval); - } - offset[0] = originalX; - } - - protected void calculateStatistics(List compareValues, double originalVal) { - shuffledPearsonsNotLessOriginal = 0; - int iterations = shuffledPearsonsResults.size(); - double compareSum = 0.0; - - for( Double shuffledVal : shuffledPearsonsResults ) { - double diff = shuffledVal - originalVal; - /* check if the randomized Pearsons value is equal - * or larger than the original one. - */ - if( diff > -0.00001 ) { - shuffledPearsonsNotLessOriginal++; - } - compareSum += shuffledVal; - } - - shuffledMean = compareSum / iterations; - shuffledStdDerivation = Statistics.stdDeviation(compareValues); - - // get the quantile of the original value in the shuffle distribution - costesPValue = Statistics.phi(originalVal, shuffledMean, shuffledStdDerivation); - - if (costesPValue > 1.0) - costesPValue = 1.0; - else if (costesPValue < 0.0) - costesPValue = 0.0; - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - - // if desired, show the last shuffled image available - if ( showShuffledImages ) { - handler.handleImage( smoothedShuffledImage, "Smoothed & shuffled channel 1" ); - } - - handler.handleValue("Costes P-Value", costesPValue, 2); - handler.handleValue("Costes Shuffled Mean", shuffledMean, 2); - handler.handleValue("Costes Shuffled Std.D.", shuffledStdDerivation, 2); - - /* give the ratio of results at least as large as the - * original value. - */ - double ratio = 0.0; - if (shuffledPearsonsNotLessOriginal > 0) { - ratio = (double)shuffledPearsonsResults.size() / (double)shuffledPearsonsNotLessOriginal; - } - handler.handleValue("Ratio of rand. Pearsons >= actual Pearsons value ", ratio, 2); - } - - public double getCostesPValue() { - return costesPValue; - } - - public double getShuffledMean() { - return shuffledMean; - } - - public double getShuffledStdDerivation() { - return shuffledStdDerivation; - } - - public double getShuffledPearsonsNotLessOriginal() { - return shuffledPearsonsNotLessOriginal; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/Histogram2D.java b/src/main/java/sc/fiji/coloc/algorithms/Histogram2D.java deleted file mode 100644 index 79a8b0a..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/Histogram2D.java +++ /dev/null @@ -1,415 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import ij.measure.ResultsTable; - -import java.util.EnumSet; - -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.LongType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.ResultHandler; - -/** - * Represents the creation of a 2D histogram between two images. - * Channel 1 is set out in x direction, while channel 2 in y direction. - * @param The source images value type - */ -public class Histogram2D> extends Algorithm { - // An enumeration of possible drawings - public enum DrawingFlags { Plot, RegressionLine, Axes } - // the drawing configuration - EnumSet drawingSettings; - - // The width of the scatter-plot - protected int xBins = 256; - // The height of the scatter-plot - protected int yBins = 256; - // The name of the result 2D histogram to pass elsewhere - protected String title = ""; - // Swap or not swap ch1 and ch2 - protected boolean swapChannels = false; - // member variables for labeling - protected String ch1Label = "Channel 1"; - protected String ch2Label = "Channel 2"; - - // Result keeping members - - // the generated plot image - private RandomAccessibleInterval plotImage; - // the bin widths for each channel - private double xBinWidth = 0.0, yBinWidth = 0.0; - // labels for the axes - private String xLabel = "", yLabel = ""; - // ranges for the axes - private double xMin = 0.0, xMax = 0.0, yMin = 0.0, yMax = 0.0; - - - public Histogram2D(){ - this("2D Histogram"); - } - - public Histogram2D(String title){ - this(title, false); - } - - public Histogram2D(String title, boolean swapChannels){ - this(title, swapChannels, EnumSet.of( DrawingFlags.Plot, DrawingFlags.RegressionLine )); - } - - public Histogram2D(String title, boolean swapChannels, EnumSet drawingSettings){ - super(title); - this.title = title; - this.swapChannels = swapChannels; - - if (swapChannels) { - int xBins = this.xBins; - this.xBins = this.yBins; - this.yBins = xBins; - } - - this.drawingSettings = drawingSettings; - } - - /** - * Gets the minimum of channel one. Takes channel - * swapping into consideration and will return min - * of channel two if swapped. - * - * @return The minimum of what is seen as channel one. - */ - protected double getMinCh1(DataContainer container) { - return swapChannels ? container.getMinCh2() : container.getMinCh1(); - } - - /** - * Gets the minimum of channel two. Takes channel - * swapping into consideration and will return min - * of channel one if swapped. - * - * @return The minimum of what is seen as channel two. - */ - protected double getMinCh2(DataContainer container) { - return swapChannels ? container.getMinCh1() : container.getMinCh2(); - } - - /** - * Gets the maximum of channel one. Takes channel - * swapping into consideration and will return max - * of channel two if swapped. - * - * @return The maximum of what is seen as channel one. - */ - protected double getMaxCh1(DataContainer container) { - return swapChannels ? container.getMaxCh2() : container.getMaxCh1(); - } - - /** - * Gets the maximum of channel two. Takes channel - * swapping into consideration and will return max - * of channel one if swapped. - * - * @return The maximum of what is seen as channel two. - */ - protected double getMaxCh2(DataContainer container) { - return swapChannels ? container.getMaxCh1() : container.getMaxCh2(); - } - - /** - * Gets the image of channel one. Takes channel - * swapping into consideration and will return image - * of channel two if swapped. - * - * @return The image of what is seen as channel one. - */ - protected RandomAccessibleInterval getImageCh1(DataContainer container) { - return swapChannels ? container.getSourceImage2() : container.getSourceImage1(); - } - - /** - * Gets the image of channel two. Takes channel - * swapping into consideration and will return image - * of channel one if swapped. - * - * @return The image of what is seen as channel two. - */ - protected RandomAccessibleInterval getImageCh2(DataContainer container) { - return swapChannels ? container.getSourceImage1() : container.getSourceImage2(); - } - - /** - * Gets the label of channel one. Takes channel - * swapping into consideration and will return label - * of channel two if swapped. - * - * @return The label of what is seen as channel one. - */ - protected String getLabelCh1() { - return swapChannels ? ch2Label : ch1Label; - } - - /** - * Gets the label of channel two. Takes channel - * swapping into consideration and will return label - * of channel one if swapped. - * - * @return The label of what is seen as channel two. - */ - protected String getLabelCh2() { - return swapChannels ? ch1Label : ch2Label; - } - - @Override - public void execute(DataContainer container) throws MissingPreconditionException { - generateHistogramData(container); - } - - protected void generateHistogramData(DataContainer container) { - double ch1BinWidth = getXBinWidth(container); - double ch2BinWidth = getYBinWidth(container); - - // get the 2 images for the calculation of Pearson's - final RandomAccessibleInterval img1 = getImageCh1(container); - final RandomAccessibleInterval img2 = getImageCh2(container); - final RandomAccessibleInterval mask = container.getMask(); - - // get the cursors for iterating through pixels in images - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - - // create new image to put the scatter-plot in - final ImgFactory scatterFactory = new ArrayImgFactory< LongType >(); - plotImage = scatterFactory.create(new int[] {xBins, yBins}, new LongType() ); - - // create access cursors - final RandomAccess histogram2DCursor = - plotImage.randomAccess(); - - long ignoredPixelCount = 0; - - // iterate over images - long[] pos = new long[ plotImage.numDimensions() ]; - while (cursor.hasNext()) { - cursor.fwd(); - double ch1 = cursor.getFirst().getRealDouble(); - double ch2 = cursor.getSecond().getRealDouble(); - /* Scale values for both channels to fit in the range. - * Moreover mirror the y value on the x axis. - */ - pos[0] = getXValue(ch1, ch1BinWidth, ch2, ch2BinWidth); - pos[1] = getYValue(ch1, ch1BinWidth, ch2, ch2BinWidth); - - if (pos[0] >= 0 && pos[1] >=0 && pos[0] < xBins && pos[1] < yBins) { - // set position of input/output cursor - histogram2DCursor.setPosition( pos ); - // get current value at position and increment it - long count = histogram2DCursor.get().getIntegerLong(); - count++; - - histogram2DCursor.get().set(count); - } else { - ignoredPixelCount ++; - } - } - - if (ignoredPixelCount > 0) { - addWarning("Ignored pixels while generating histogram.", - "" + ignoredPixelCount + " pixels were ignored while generating the 2D histogram \"" + title + - "\" because the grey values were out of range." + - "This may happen, if an image contains negative pixel values."); - } - xBinWidth = ch1BinWidth; - yBinWidth = ch2BinWidth; - xLabel = getLabelCh1(); - yLabel = getLabelCh2(); - xMin = getXMin(container); - xMax = getXMax(container); - yMin = getYMin(container); - yMax = getYMax(container); - } - - /** - * A table of x-values, y-values and the counts is generated and - * returned as a string. The single fields in one row (X Y Count) - * are separated by tabs. - * - * @return A String representation of the histogram data. - */ - public String getData() { - StringBuffer sb = new StringBuffer(); - - double xBinWidth = 1.0 / getXBinWidth(); - double yBinWidth = 1.0 / getYBinWidth(); - double xMin = getXMin(); - double yMin = getYMin(); - // check if we have bins of size one or other ones - boolean xBinWidthIsOne = Math.abs(xBinWidth - 1.0) < 0.00001; - boolean yBinWidthIsOne = Math.abs(yBinWidth - 1.0) < 0.00001; - // configure decimal places accordingly - int xDecimalPlaces = xBinWidthIsOne ? 0 : 3; - int yDecimalPlaces = yBinWidthIsOne ? 0 : 3; - // create a cursor to access the histogram data - RandomAccess cursor = plotImage.randomAccess(); - // loop over 2D histogram - for (int i=0; i < plotImage.dimension(0); ++i) { - for (int j=0; j < plotImage.dimension(1); ++j) { - cursor.setPosition(i, 0); - cursor.setPosition(j, 1); - sb.append( - ResultsTable.d2s(xMin + (i * xBinWidth), xDecimalPlaces) + "\t" + - ResultsTable.d2s(yMin + (j * yBinWidth), yDecimalPlaces) + "\t" + - ResultsTable.d2s(cursor.get().getRealDouble(), 0) + "\n"); - } - } - - return sb.toString(); - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - - handler.handleHistogram( this, title ); - } - - /** - * Calculates the bin width of one bin in x/ch1 direction. - * @param container The container with images to work on - * @return The width of one bin in x direction - */ - protected double getXBinWidth(DataContainer container) { - double ch1Max = getMaxCh1(container); - if (ch1Max < yBins) { - // bin widths must not exceed 1 - return 1; - } - // we need (ch1Max * width + 0.5) < yBins, but just so, i.e. - // ch1Max * width + 0.5 == yBins - eps - // width = (yBins - 0.5 - eps) / ch1Max - return (yBins - 0.50001) / ch1Max; - } - - /** - * Calculates the bin width of one bin in y/ch2 direction. - * @param container The container with images to work on - * @return The width of one bin in y direction - */ - protected double getYBinWidth(DataContainer container) { - double ch2Max = getMaxCh2(container); - if (ch2Max < yBins) { - // bin widths must not exceed 1 - return 1; - } - return (yBins - 0.50001) / ch2Max; - } - - /** - * Calculates the locations x value. - * @param ch1Val The intensity of channel one - * @param ch1BinWidth The bin width for channel one - * @return The x value of the data point location - */ - protected int getXValue(double ch1Val, double ch1BinWidth, double ch2Val, double ch2BinWidth) { - return (int)(ch1Val * ch1BinWidth + 0.5); - } - - /** - * Calculates the locations y value. - * @param ch2Val The intensity of channel one - * @param ch2BinWidth The bin width for channel one - * @return The x value of the data point location - */ - protected int getYValue(double ch1Val, double ch1BinWidth, double ch2Val, double ch2BinWidth) { - return (yBins - 1) - (int)(ch2Val * ch2BinWidth + 0.5); - } - - protected double getXMin(DataContainer container) { - return 0; - } - - protected double getXMax(DataContainer container) { - return swapChannels ? getMaxCh2(container) : getMaxCh1(container); - } - - protected double getYMin(DataContainer container) { - return 0; - } - - protected double getYMax(DataContainer container) { - return swapChannels ? getMaxCh1(container) : getMaxCh2(container); - } - - // Result access methods - - public RandomAccessibleInterval getPlotImage() { - return plotImage; - } - - public double getXBinWidth() { - return xBinWidth; - } - - public double getYBinWidth() { - return yBinWidth; - } - - public String getXLabel() { - return xLabel; - } - - public String getYLabel() { - return yLabel; - } - - public double getXMin() { - return xMin; - } - - public double getXMax() { - return xMax; - } - - public double getYMin() { - return yMin; - } - - public double getYMax() { - return yMax; - } - - public String getTitle() { - return title; - } - - public EnumSet getDrawingSettings() { - return drawingSettings; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/InputCheck.java b/src/main/java/sc/fiji/coloc/algorithms/InputCheck.java deleted file mode 100644 index c090202..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/InputCheck.java +++ /dev/null @@ -1,207 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import ij.IJ; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.DataContainer.MaskType; -import sc.fiji.coloc.results.ResultHandler; - -/** - * This class implements some basic checks for the input image data. For - * instance: Is the percentage of zero-zero or saturated pixels too high? Also, - * we get basic image properties / stats from imglib2, and also the - * colocalization job name from the DataContainer and allow implementations of - * ResultHandler to report them. - */ -public class InputCheck> extends Algorithm { - /* the maximum allowed ratio between zero-zero and - * normal pixels - */ - protected final double maxZeroZeroRatio = 0.1f; - /* the maximum allowed ratio between saturated and - * normal pixels within a channel - */ - protected final double maxSaturatedRatio = 0.1f; - // the zero-zero pixel ratio - double zeroZeroPixelRatio; - // the saturated pixel ratio of channel 1 - double saturatedRatioCh1; - // the saturated pixel ratio of channel 2 - double saturatedRatioCh2; - - // the coloc job name - String colocJobName; - - // general image stats/parameters/values - double ch1Max; - double ch2Max; - double ch1Min; - double ch2Min; - double ch1Mean; - double ch2Mean; - double ch1Integral; - double ch2Integral; - - // Mask infos - MaskType maskType; - double maskID; - - public InputCheck() { - super("input data check"); - } - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - // get the 2 images and the mask - final RandomAccessibleInterval img1 = container.getSourceImage1(); - final RandomAccessibleInterval img2 = container.getSourceImage2(); - final RandomAccessibleInterval mask = container.getMask(); - - // get the cursors for iterating through pixels in images - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).cursor()); - - // get various general image properties/stats/values from the DataContainer - ch1Max = container.getMaxCh1(); - ch2Max = container.getMaxCh2(); - ch1Min = container.getMinCh1(); - ch2Min = container.getMinCh2(); - ch1Mean = container.getMeanCh1(); - ch2Mean = container.getMeanCh2(); - ch1Integral = container.getIntegralCh1(); - ch2Integral = container.getIntegralCh2(); - - // get the info about the mask/ROI being used or not. - maskType = container.getMaskType(); - maskID = (double)container.getMaskID(); - - // the total amount of pixels that have been taken into consideration - long N = 0; - // the number of pixels that are zero in both channels - long Nzero = 0; - // the number of ch1 pixels with the maximum ch1 value; - long NsaturatedCh1 = 0; - // the number of ch2 pixels with the maximum ch2 value; - long NsaturatedCh2 = 0; - - while (cursor.hasNext()) { - cursor.fwd(); - double ch1 = cursor.getFirst().getRealDouble(); - double ch2 = cursor.getSecond().getRealDouble(); - - // is the current pixels combination a zero-zero pixel? - if (Math.abs(ch1 + ch2) < 0.00001) - Nzero++; - - // is the current pixel of channel one saturated? - if (Math.abs(ch1Max - ch1) < 0.00001) - NsaturatedCh1++; - - // is the current pixel of channel one saturated? - if (Math.abs(ch2Max - ch2) < 0.00001) - NsaturatedCh2++; - - N++; - } - - // calculate results - double zeroZeroRatio = (double)Nzero / (double)N; - // for channel wise ratios we have to use half of the total pixel amount - double ch1SaturatedRatio = (double)NsaturatedCh1 / ( (double)N *0.5); - double ch2SaturatedRatio = (double)NsaturatedCh2 / ( (double)N * 0.5); - - /* save results - * Percentage results need to be multiplied by 100 - */ - zeroZeroPixelRatio = zeroZeroRatio * 100.0; - saturatedRatioCh1 = ch1SaturatedRatio * 100.0; - saturatedRatioCh2 = ch2SaturatedRatio * 100.0; - - // get job name so the ResultsHandler implementation can have it. - colocJobName = container.getJobName(); - - // add warnings if images contain negative values - if (ch1Min < 0 || ch2Min < 0) { - addWarning("Negative minimum pixel value found.", - "The minimum pixel value in at least one of the channels is negative. Negative values might break the logic of some analysis methods by breaking a basic basic assumption: The pixel value is assumed to be proportional to the number of photons detected in a pixel. Negative photon counts make no physical sense. Set negative pixel values to zero, or shift pixel intensities higher so there are no negative pixel values."); - } - - // add warnings if values are not in tolerance range - if ( Math.abs(zeroZeroRatio) > maxZeroZeroRatio ) { - - addWarning("Zero-zero ratio too high", - "The ratio between zero-zero pixels and other pixels is large: " - + IJ.d2s(zeroZeroRatio, 2) + ". Maybe you should use a ROI."); - } - if ( Math.abs(ch1SaturatedRatio) > maxSaturatedRatio ) { - addWarning("Saturated ch1 ratio too high", - "The ratio between saturated pixels and other pixels in channel one is large: " - + IJ.d2s(maxSaturatedRatio, 2) + ". Maybe you should use a ROI."); - } - if ( Math.abs(ch1SaturatedRatio) > maxSaturatedRatio ) { - addWarning("Saturated ch2 ratio too high", - "The ratio between saturated pixels and other pixels in channel two is large: " - + IJ.d2s(maxSaturatedRatio, 2) + ". Maybe you should use a ROI."); - } - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - - // Let us have a ValueResult for the colocalisation analysis job name: - // A ValueResult can be two Strings (or a string and a numerical value) - // We want to keep the jobName close to all the value results - // so they get shown together by whatever implementation of ResultsHandler. - handler.handleValue("Coloc_Job_Name", colocJobName); - - // Make the ResultsHander implementation deal with the input check results. - handler.handleValue("% zero-zero pixels", zeroZeroPixelRatio, 2); - handler.handleValue("% saturated ch1 pixels", saturatedRatioCh1, 2); - handler.handleValue("% saturated ch2 pixels", saturatedRatioCh2, 2); - - // Make the ResultsHander implementation deal with the images' - // stats/parameters/values - handler.handleValue("Channel 1 Max", ch1Max, 3); - handler.handleValue("Channel 2 Max", ch2Max, 3); - handler.handleValue("Channel 1 Min", ch1Min, 3); - handler.handleValue("Channel 2 Min", ch2Min, 3); - handler.handleValue("Channel 1 Mean", ch1Mean, 3); - handler.handleValue("Channel 2 Mean", ch2Mean, 3); - handler.handleValue("Channel 1 Integrated (Sum) Intensity", ch1Integral, 3); - handler.handleValue("Channel 2 Integrated (Sum) Intensity", ch2Integral, 3); - - // Make the ResultsHandler implementation deal with the images' - // ROI or mask or lack thereof, so the user knows what they used. - handler.handleValue("Mask Type Used", maskType.label()); - handler.handleValue("Mask ID Used", maskID, 0); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/IntArraySorter.java b/src/main/java/sc/fiji/coloc/algorithms/IntArraySorter.java deleted file mode 100644 index 9c8a4e9..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/IntArraySorter.java +++ /dev/null @@ -1,139 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * Sorts and int[] according to a custom comparator. - *

- * This is an implementation of introsort, i.e. it is stable because - * it tries the quicksort algorithm first and falls back to the heap - * sort when it detects an unfavorable execution path. - *

- * - * @author Johannes Schindelin - */ -public class IntArraySorter { - - private final static int SORT_SIZE_THRESHOLD = 16; - - public static void sort(int[] array, IntComparator comparator) { - introSort(array, comparator, 0, array.length, array.length); - insertionSort(array, comparator); - } - - private static void introSort(int[] array, IntComparator comparator, int begin, int end, int limit) - { - while (end - begin > SORT_SIZE_THRESHOLD) { - if (limit == 0) { - heapSort(array, comparator, begin, end); - return; - } - limit >>= 1; - - // median of three - int a = array[begin]; - int b = array[begin + (end - begin) / 2 + 1]; - int c = array[end - 1]; - int median; - if (comparator.compare(a, b) < 0) { - median = comparator.compare(b, c) < 0 ? - b : (comparator.compare(a, c) < 0 ? c : a); - } else { - median = comparator.compare(b, c) > 0 ? - b : (comparator.compare(a, c) > 0 ? c : a); - } - - // partition - int pivot, i = begin, j = end; - for (;;) { - while (comparator.compare(array[i], median) < 0) { - ++i; - } - --j; - while (comparator.compare(median, array[j]) < 0) { - --j; - } - if (i >= j) { - pivot = i; - break; - } - int swap = array[i]; - array[i] = array[j]; - array[j] = swap; - ++i; - } - - introSort(array, comparator, pivot, end, limit); - end = pivot; - } - } - - private static void heapSort(int[] array, IntComparator comparator, - int begin, int end) - { - int count = end - begin; - for (int i = count / 2 - 1; i >= 0; --i) { - siftDown(array, comparator, i, count, begin); - } - for (int i = count - 1; i > 0; --i) { - // swap begin and begin + i - int swap = array[begin + i]; - array[begin + i] = array[begin]; - array[begin] = swap; - - siftDown(array, comparator, 0, i, begin); - } - } - - private static void siftDown(int[] array, IntComparator comparator, - int i, int count, int offset) - { - int value = array[offset + i]; - while (i < count / 2) { - int child = 2 * i + 1; - if (child + 1 < count && - comparator.compare(array[child], array[child + 1]) < 0) { - ++child; - } - if (comparator.compare(value, array[child]) >= 0) { - break; - } - array[offset + i] = array[offset + child]; - i = child; - } - array[offset + i] = value; - } - - private static void insertionSort(int[] array, - IntComparator comparator) - { - for (int j = 1; j < array.length; ++j) { - int t = array[j]; - int i = j - 1; - while (i >= 0 && comparator.compare(array[i], t) > 0) { - array[i + 1] = array[i]; - i = i - 1; - } - array[i + 1] = t; - } - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/IntComparator.java b/src/main/java/sc/fiji/coloc/algorithms/IntComparator.java deleted file mode 100644 index 1d7a615..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/IntComparator.java +++ /dev/null @@ -1,26 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -public interface IntComparator { - int compare(int a, int b); -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/KendallTauRankCorrelation.java b/src/main/java/sc/fiji/coloc/algorithms/KendallTauRankCorrelation.java deleted file mode 100644 index d9caa4e..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/KendallTauRankCorrelation.java +++ /dev/null @@ -1,363 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import ij.IJ; - -import java.util.Arrays; - -import net.imglib2.PairIterator; -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.ResultHandler; - -/** - * This algorithm calculates Kendall's Tau-b rank correlation coefficient - *

- * According to this - * article, Tau-b (appropriate if multiple pairs share the same first, or - * second, value), the rank correlation of a set of pairs (x_1, y_1), ..., - * (x_n, y_n): - *

- * - *
- * Tau_B = (n_c - n_d) / sqrt( (n_0 - n_1) (n_0 - n_2) )
- * 
- * - * where - * - *
- * n_0 = n (n - 1) / 2
- * n_1 = sum_i t_i (t_i - 1) / 2
- * n_2 = sum_j u_j (u_j - 1) / 2
- * n_c = #{ i, j; i != j && (x_i - x_j) * (y_i - y_j) > 0 },
- *   i.e. the number of pairs of pairs agreeing on the order of x and y, respectively
- * n_d = #{ i, j: i != j && (x_i - x_j) * (y_i - y_j) < 0 },
- *   i.e. the number of pairs of pairs where x and y are ordered opposite of each other
- * t_i = number of tied values in the i-th group of ties for the first quantity
- * u_j = number of tied values in the j-th group of ties for the second quantity
- * 
- * - * @author Johannes Schindelin - * @param - */ -public class KendallTauRankCorrelation> extends Algorithm { - - public KendallTauRankCorrelation() { - super("Kendall's Tau-b Rank Correlation"); - } - - private double tau; - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException - { - RandomAccessible img1 = container.getSourceImage1(); - RandomAccessible img2 = container.getSourceImage2(); - RandomAccessibleInterval mask = container.getMask(); - - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - - tau = calculateMergeSort(cursor); - } - - public static> double calculateNaive(final PairIterator iterator) { - if (!iterator.hasNext()) { - return Double.NaN; - } - - // See http://en.wikipedia.org/wiki/Kendall_tau_rank_correlation_coefficient - int n = 0, max1 = 0, max2 = 0, max = 255; - int[][] histogram = new int[max + 1][max + 1]; - while (iterator.hasNext()) { - iterator.fwd(); - T type1 = iterator.getFirst(); - T type2 = iterator.getSecond(); - double ch1 = type1.getRealDouble(); - double ch2 = type2.getRealDouble(); - if (ch1 < 0 || ch2 < 0 || ch1 > max || ch2 > max) { - IJ.log("Error: The current Kendall Tau implementation is limited to 8-bit data"); - return Double.NaN; - } - n++; - int ch1Int = (int)Math.round(ch1); - int ch2Int = (int)Math.round(ch2); - histogram[ch1Int][ch2Int]++; - if (max1 < ch1Int) { - max1 = ch1Int; - } - if (max2 < ch2Int) { - max2 = ch2Int; - } - } - long n0 = n * (long)(n - 1) / 2, n1 = 0, n2 = 0, nc = 0, nd = 0; - for (int i1 = 0; i1 <= max1; i1++) { - IJ.log("" + i1 + "/" + max1); - int ch1 = 0; - for (int i2 = 0; i2 <= max2; i2++) { - ch1 += histogram[i1][i2]; - - int count = histogram[i1][i2]; - for (int j1 = 0; j1 < i1; j1++) { - for (int j2 = 0; j2 < i2; j2++) { - nc += count * histogram[j1][j2]; - } - } - for (int j1 = 0; j1 < i1; j1++) { - for (int j2 = i2 + 1; j2 <= max2; j2++) { - nd += count * histogram[j1][j2]; - } - } - } - n1 += ch1 * (long)(ch1 - 1) / 2; - } - for (int i2 = 0; i2 <= max2; i2++) { - int ch2 = 0; - for (int i1 = 0; i1 <= max1; i1++) { - ch2 += histogram[i1][i2]; - } - n2 += ch2 * (long)(ch2 - 1) / 2; - } - - return (nc - nd) / Math.sqrt((n0 - n1) * (double)(n0 - n2)); - } - - private static> double[][] getPairs(final PairIterator iterator) { - // TODO: it is ridiculous that this has to be counted all the time (i.e. in most if not all measurements!). - // We only need an upper bound to begin with, so even the number of pixels in the first channel would be enough! - int capacity = 0; - while (iterator.hasNext()) { - iterator.fwd(); - capacity++; - } - - double[] values1 = new double[capacity]; - double[] values2 = new double[capacity]; - iterator.reset(); - int count = 0; - while (iterator.hasNext()) { - iterator.fwd(); - values1[count] = iterator.getFirst().getRealDouble(); - values2[count] = iterator.getSecond().getRealDouble(); - count++; - } - - if (count < capacity) { - values1 = Arrays.copyOf(values1, count); - values2 = Arrays.copyOf(values2, count); - } - return new double[][] { values1, values2 }; - } - - /** - * Calculate Tau-b efficiently. - *

- * This implementation is based on this - * description of the merge sort based way to calculate Tau-b. This is - * supposed to be the method described in: - *

- *
Knight, W. (1966). "A Computer Method for Calculating - * Kendall's Tau with Ungrouped Data". Journal of the American Statistical - * Association 61 (314): 436–439. doi:10.2307/2282833.
- *

- * but since that article is not available as Open Access, it is - * unnecessarily hard to verify. - *

- * - * @param iterator the iterator of the pairs - * @return Tau-b - */ - public static> double calculateMergeSort(final PairIterator iterator) { - final double[][] pairs = getPairs(iterator); - final double[] x = pairs[0]; - final double[] y = pairs[1]; - final int n = x.length; - - int[] index = new int[n]; - for (int i = 0; i < n; i++) { - index[i] = i; - } - - // First sort by x as primary key, y as secondary one. - // We use IntroSort here because it is fast and in-place. - IntArraySorter.sort(index, new IntComparator() { - - @Override - public int compare(int a, int b) { - double xa = x[a], ya = y[a]; - double xb = x[b], yb = y[b]; - int result = Double.compare(xa, xb); - return result != 0 ? result : Double.compare(ya, yb); - } - - }); - - // The trick is to count the ties of x (n1) and the joint ties of x and y (n3) now, while - // index is sorted with regards to x. - long n0 = n * (long)(n - 1) / 2; - long n1 = 0, n3 = 0; - - for (int i = 1; i < n; i++) { - double x0 = x[index[i - 1]]; - if (x[index[i]] != x0) { - continue; - } - double y0 = y[index[i - 1]]; - int i1 = i; - do { - double y1 = y[index[i1++]]; - if (y1 == y0) { - int i2 = i1; - while (i1 < n && x[index[i1]] == x0 && y[index[i1]] == y0) { - i1++; - } - n3 += (i1 - i2 + 2) * (long)(i1 - i2 + 1) / 2; - } - y0 = y1; - } while (i1 < n && x[index[i1]] == x0); - n1 += (i1 - i + 1) * (long)(i1 - i) / 2; - i = i1; - } - - // Now, let's perform that merge sort that also counts S, the number of - // swaps a Bubble Sort would require (and which therefore is half the number - // by which we have to adjust n_0 - n_1 - n_2 + n_3 to obtain n_c - n_d) - final MergeSort mergeSort = new MergeSort(index, new IntComparator() { - - @Override - public int compare(int a, int b) { - double ya = y[a]; - double yb = y[b]; - return Double.compare(ya, yb); - } - }); - long S = mergeSort.sort(); - index = mergeSort.getSorted(); - long n2 = 0; - - for (int i = 1; i < n; i++) { - double y0 = y[index[i - 1]]; - if (y[index[i]] != y0) { - continue; - } - int i1 = i + 1; - while (i1 < n && y[index[i1]] == y0) { - i1++; - } - n2 += (i1 - i + 1) * (long)(i1 - i) / 2; - i = i1; - } - - return (n0 - n1 - n2 + n3 - 2 * S) / Math.sqrt((n0 - n1) * (double)(n0 - n2)); - } - - private final static class MergeSort { - - private int[] index; - private final IntComparator comparator; - - public MergeSort(int[] index, IntComparator comparator) { - this.index = index; - this.comparator = comparator; - } - - public int[] getSorted() { - return index; - } - - /** - * Sorts the {@link #index} array. - *

- * This implements a non-recursive merge sort. - *

- * @param begin - * @param end - * @return the equivalent number of BubbleSort swaps - */ - public long sort() { - long swaps = 0; - int n = index.length; - // There are merge sorts which perform in-place, but their runtime is worse than O(n log n) - int[] index2 = new int[n]; - for (int step = 1; step < n; step <<= 1) { - int begin = 0, k = 0; - for (;;) { - int begin2 = begin + step, end = begin2 + step; - if (end >= n) { - if (begin2 >= n) { - break; - } - end = n; - } - - // calculate the equivalent number of BubbleSort swaps - // and perform merge, too - int i = begin, j = begin2; - while (i < begin2 && j < end) { - int compare = comparator.compare(index[i], index[j]); - if (compare > 0) { - swaps += (begin2 - i); - index2[k++] = index[j++]; - } else { - index2[k++] = index[i++]; - } - } - if (i < begin2) { - do { - index2[k++] = index[i++]; - } while (i < begin2); - } else { - while (j < end) { - index2[k++] = index[j++]; - } - } - begin = end; - } - if (k < n) { - System.arraycopy(index, k, index2, k, n - k); - } - int[] swapIndex = index2; - index2 = index; - index = swapIndex; - } - - return swaps; - } - - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - handler.handleValue("Kendall's Tau-b rank correlation value", tau, 4); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/LiHistogram2D.java b/src/main/java/sc/fiji/coloc/algorithms/LiHistogram2D.java deleted file mode 100644 index 6f50f9d..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/LiHistogram2D.java +++ /dev/null @@ -1,173 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import java.util.EnumSet; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; - -/** - * Represents the creation of a 2D histogram between two images. - * Channel 1 is set out in x direction, while channel 2 in y direction. - * The value calculation is done after Li. - * @param - */ -public class LiHistogram2D> extends Histogram2D { - // On execution these variables hold the images means - double ch1Mean, ch2Mean; - - // On execution these variables hold the images min and max - double ch1Min, ch1Max, ch2Min, ch2Max; - - // On execution these variables hold the Li's value min and max and their difference - double liMin, liMax, liDiff; - - // On execution these variables hold the scaling factors - double ch1Scaling, ch2Scaling; - - // boolean to test which channel we are using for eg. Li 2D histogram y axis - boolean useCh1 = true; - - public LiHistogram2D(boolean useCh1) { - this("Histogram 2D (Li)", useCh1); - } - - public LiHistogram2D(String title, boolean useCh1) { - this(title, false, useCh1); - } - - public LiHistogram2D(String title, boolean swapChannels, boolean useCh1) { - this(title, swapChannels, useCh1, EnumSet.of(DrawingFlags.Plot)); - } - - public LiHistogram2D(String title, boolean swapChannels, boolean useCh1, EnumSet drawingSettings) { - super(title, swapChannels, drawingSettings); - this.useCh1 = useCh1; - } - - @Override - public void execute(DataContainer container) throws MissingPreconditionException { - ch1Mean = swapChannels ? container.getMeanCh2() : container.getMeanCh1(); - ch2Mean = swapChannels ? container.getMeanCh1() : container.getMeanCh2(); - - ch1Min = getMinCh1(container); - ch1Max = getMaxCh1(container); - - ch2Min = getMinCh2(container); - ch2Max = getMaxCh2(container); - - /* A scaling to the x bins has to be made: - * For that to work we need the min and the - * max value that could occur. - */ - - // get the 2 images and the mask - final RandomAccessibleInterval img1 = getImageCh1(container); - final RandomAccessibleInterval img2 = getImageCh2(container); - final RandomAccessibleInterval mask = container.getMask(); - - // get the cursors for iterating through pixels in images - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - - // give liMin and liMax appropriate starting values at the top and bottom of the range - liMin = Double.MAX_VALUE; - liMax = Double.MIN_VALUE; - - // iterate over images - while (cursor.hasNext()) { - cursor.fwd(); - double ch1 = cursor.getFirst().getRealDouble(); - double ch2 = cursor.getSecond().getRealDouble(); - - double productOfDifferenceOfMeans = (ch1Mean - ch1) * (ch2Mean - ch2); - - if (productOfDifferenceOfMeans < liMin) - liMin = productOfDifferenceOfMeans; - if (productOfDifferenceOfMeans > liMax) - liMax = productOfDifferenceOfMeans; - } - liDiff = Math.abs(liMax - liMin); - - generateHistogramData(container); - } - - @Override - protected double getXBinWidth(DataContainer container) { - return (double) xBins / (double)(liDiff + 1); - } - - @Override - protected double getYBinWidth(DataContainer container) { - double max; - if (useCh1) { - max = getMaxCh1(container); - } - else { - max = getMaxCh2(container); - } - return (double) yBins / (double)(max + 1); - } - - @Override - protected int getXValue(double ch1Val, double ch1BinWidth, double ch2Val, double ch2BinWidth) { - /* We want the values to be scaled and shifted by and - * offset in a way that the smallest (possibly negative) - * value is in first bin and highest value in largest bin. - */ - return (int)( (( (ch1Mean - ch1Val) * (ch2Mean - ch2Val)) - liMin) * ch1BinWidth); - } - - @Override - protected int getYValue(double ch1Val, double ch1BinWidth, double ch2Val, double ch2BinWidth) { - if (useCh1) - return (yBins - 1) - (int)(ch1Val * ch2BinWidth); - else - return (yBins - 1) - (int)(ch2Val * ch2BinWidth); - } - - @Override - protected double getXMin(DataContainer container) { - return swapChannels ? (useCh1 ? container.getMinCh1(): container.getMinCh2()) : liMin; - } - - @Override - protected double getXMax(DataContainer container) { - return swapChannels ? (useCh1 ? container.getMaxCh1(): container.getMaxCh2()) : liMax; - } - - @Override - protected double getYMin(DataContainer container) { - return swapChannels ? liMin : (useCh1 ? container.getMinCh1(): container.getMinCh2()); - } - - @Override - protected double getYMax(DataContainer container) { - return swapChannels ? liMax : (useCh1 ? container.getMaxCh1(): container.getMaxCh2()); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/LiICQ.java b/src/main/java/sc/fiji/coloc/algorithms/LiICQ.java deleted file mode 100644 index b57ff80..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/LiICQ.java +++ /dev/null @@ -1,108 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.ResultHandler; - -/** - * This algorithm calculates Li et al.'s ICQ (intensity - * correlation quotient). - * - * @param - */ -public class LiICQ> extends Algorithm { - // the resulting ICQ value - double icqValue; - - public LiICQ() { - super("Li ICQ calculation"); - } - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - double mean1 = container.getMeanCh1(); - double mean2 = container.getMeanCh2(); - - // get the 2 images for the calculation of Li's ICQ - RandomAccessible img1 = container.getSourceImage1(); - RandomAccessible img2 = container.getSourceImage2(); - RandomAccessibleInterval mask = container.getMask(); - - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - // calculate ICQ value - icqValue = calculateLisICQ(cursor, mean1, mean2); - } - - /** - * Calculates Li et al.'s intensity correlation quotient (ICQ) for - * two images. - * - * @param cursor A TwinCursor that iterates over two images - * @param mean1 The first images mean - * @param mean2 The second images mean - * @return Li et al.'s ICQ value - */ - public static > double calculateLisICQ(TwinCursor cursor, double mean1, double mean2) { - /* variables to count the positive and negative results - * of Li's product of the difference of means. - */ - long numPositiveProducts = 0; - long numNegativeProducts = 0; - // iterate over image - while (cursor.hasNext()) { - cursor.fwd(); - T type1 = cursor.getFirst(); - T type2 = cursor.getSecond(); - double ch1 = type1.getRealDouble(); - double ch2 = type2.getRealDouble(); - - double productOfDifferenceOfMeans = (mean1 - ch1) * (mean2 - ch2); - - // check for positive and negative values - if (productOfDifferenceOfMeans < 0.0 ) - ++numNegativeProducts; - else - ++numPositiveProducts; - } - - /* calculate Li's ICQ value by dividing the amount of "positive pixels" to the - * total number of pixels. Then shift it in the -0.5,0.5 range. - */ - return ( (double) numPositiveProducts / (double) (numNegativeProducts + numPositiveProducts) ) - 0.5; - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - handler.handleValue("Li's ICQ value", icqValue); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/MandersColocalization.java b/src/main/java/sc/fiji/coloc/algorithms/MandersColocalization.java deleted file mode 100644 index 1b01f8f..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/MandersColocalization.java +++ /dev/null @@ -1,289 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.ThresholdMode; -import sc.fiji.coloc.results.ResultHandler; - -/** - *

This algorithm calculates Manders et al.'s split colocalization - * coefficients, M1 and M2. These are independent of signal intensities, - * but are directly proportional to the amount of - * fluorescence in the colocalized objects in each colour channel of the - * image, relative to the total amount of fluorescence in that channel. - * See "Manders, Verbeek, Aten - Measurement of colocalization - * of objects in dual-colour confocal images. J. Microscopy, vol. 169 - * pt 3, March 1993, pp 375-382".

- * - *

M1 = sum of Channel 1 intensity in pixels over the channel 2 threshold / total Channel 1 intensity. - * M2 is vice versa. - * The threshold may be everything > 0 in the other channel, which we call M1 and M2: without thresholds - * or everything above some thresholds in the opposite channels 1 or 2, called tM1 and tM2: with thresholds - * The result is a fraction (range 0-1, but often misrepresented as a %. We wont do that here.

- * - *

TODO: Further, it could/should/will calculate other split colocalization coefficients, - * such as fraction of pixels (voxels) colocalized, - * or fraction of intensity colocalized, as described at: - * WCIF - * copy pasted here - credits to Tony Collins.

- * - *

Number of colocalised voxels - Ncoloc - * This is the number of voxels which have both channel 1 and channel 2 intensities above threshold - * (i.e., the number of pixels in the yellow area of the scatterplot).

- * - *

%Image volume colocalised - %Volume - * This is the percentage of voxels which have both channel 1 and channel 2 intensities above threshold, - * expressed as a percentage of the total number of pixels in the image (including zero-zero pixels); - * in other words, the number of pixels in the scatterplot's yellow area / total number of pixels in the scatter plot (the Red + Green + Blue + Yellow areas).

- * - *

%Voxels Colocalised - %Ch1 Vol; %Ch2 Vol - * This generates a value for each channel. This is the number of voxels for each channel - * which have both channel 1 and channel 2 intensities above threshold, - * expressed as a percentage of the total number of voxels for each channel - * above their respective thresholds; in other words, for channel 1 (along the x-axis), - * this equals the (the number of pixels in the Yellow area) / (the number of pixels in the Blue + Yellow areas). - * For channel 2 this is calculated as follows: - * (the number of pixels in the Yellow area) / (the number of pixels in the Red + Yellow areas).

- * - *

%Intensity Colocalised - %Ch1 Int; %Ch2 Int - * This generates a value for each channel. For channel 1, this value is equal to - * the sum of the pixel intensities, with intensities above both channel 1 and channel 2 thresholds - * expressed as a percentage of the sum of all channel 1 intensities; - * in other words, it is calculated as follows: - * (the sum of channel 1 pixel intensities in the Yellow area) / (the sum of channel 1 pixels intensities in the Red + Green + Blue + Yellow areas).

- * - *

%Intensities above threshold colocalised - %Ch1 Int > thresh; %Ch2 Int > thresh - * This generates a value for each channel. For channel 1, - * this value is equal to the sum of the pixel intensities - * with intensities above both channel 1 and channel 2 thresholds - * expressed as a percentage of the sum of all channel 1 intensities above the threshold for channel 1. - * In other words, it is calculated as follows: - * (the sum of channel 1 pixel intensities in the Yellow area) / (sum of channel 1 pixels intensities in the Blue + Yellow area)

- * - *

The results are often represented as % values, but to make them consistent with Manders' - * split coefficients, we will also report them as fractions (range 0-1). - * Perhaps this helps prevent the confusion in comparisons of results - * caused by one person's %coloc being a totally - * different measurement than another person's %coloc.

- * - * @param - */ -public class MandersColocalization> extends Algorithm { - // Manders' split coefficients, M1 and M2: without thresholds - // fraction of intensity of a channel, in pixels above zero in the other channel. - private double mandersM1, mandersM2; - - - // thresholded Manders M1 and M2 values, - // Manders' split coefficients, tM1 and tM2: with thresholds - // fraction of intensity of a channel, in pixels above threshold in the other channel. - private double mandersThresholdedM1, mandersThresholdedM2; - - // Number of colocalized voxels (pixels) - Ncoloc - private long numberOfPixelsAboveBothThresholds; - - // Fraction of Image volume colocalized - Fraction of Volume - private double fractionOfPixelsAboveBothThresholds; - - // Fraction Voxels (pixels) Colocalized - Fraction of Ch1 Vol; Fraction of Ch2 Vol - private double fractionOfColocCh1Pixels, fractionOfColocCh2Pixels; - - // Fraction Intensity Colocalized - Fraction of Ch1 Int; Fraction of Ch2 Int - private double fractionOfColocCh1Intensity, fractionOfColocCh2Intensity; - - // Fraction of Intensities above threshold, colocalized - - // Fraction of Ch1 Int > thresh; Fraction of Ch2 Int > thresh - private double fractionOfColocCh1IntensityAboveCh1Thresh, fractionOfColocCh2IntensityAboveCh2Thresh; - - /** - * A result container for Manders' calculations. - */ - public static class MandersResults { - public double m1; - public double m2; - } - - public MandersColocalization() { - super("Manders correlation"); - } - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - // get the two images for the calculation of Manders' split coefficients - RandomAccessible img1 = container.getSourceImage1(); - RandomAccessible img2 = container.getSourceImage2(); - RandomAccessibleInterval mask = container.getMask(); - - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - - // calculate Manders' split coefficients without threshold, M1 and M2. - MandersResults results = calculateMandersCorrelation(cursor, - img1.randomAccess().get().createVariable()); - - // save the results - mandersM1 = results.m1; - mandersM2 = results.m2; - - // calculate the thresholded Manders' split coefficients, tM1 and tM2, if possible - AutoThresholdRegression autoThreshold = container.getAutoThreshold(); - if (autoThreshold != null ) { - // thresholded Manders' split coefficients, tM1 and tM2 - cursor.reset(); - results = calculateMandersCorrelation(cursor, autoThreshold.getCh1MaxThreshold(), - autoThreshold.getCh2MaxThreshold(), ThresholdMode.Above); - - // save the results - mandersThresholdedM1 = results.m1; - mandersThresholdedM2 = results.m2; - } - } - - /** - * Calculates Manders' split coefficients, M1 and M2: without thresholds - * - * @param cursor A TwinCursor that walks over two images - * @param type A type instance, its value is not relevant - * @return Both Manders' split coefficients, M1 and M2. - */ - public MandersResults calculateMandersCorrelation(TwinCursor cursor, T type) { - return calculateMandersCorrelation(cursor, type, type, ThresholdMode.None); - } - - /** - * Calculates Manders' split coefficients, tM1 and tM2: with thresholds - * - * @param cursor A TwinCursor that walks over two images - * @param thresholdCh1 type T - * @param thresholdCh2 type T - * @param tMode A ThresholdMode the threshold mode - * @return Both thresholded Manders' split coefficients, tM1 and tM2. - */ - public MandersResults calculateMandersCorrelation(TwinCursor cursor, - final T thresholdCh1, final T thresholdCh2, ThresholdMode tMode) { - SplitCoeffAccumulator mandersAccum; - // create a zero-values variable to compare to later on - final T zero = thresholdCh1.createVariable(); - zero.setZero(); - - // iterate over images - set the boolean value for if a pixel is thresholded - - // without thresholds: M1 and M1 - if (tMode == ThresholdMode.None) { - mandersAccum = new SplitCoeffAccumulator(cursor) { - @Override - final boolean acceptMandersCh1(T type1, T type2) { - return (type2.compareTo(zero) > 0); - } - @Override - final boolean acceptMandersCh2(T type1, T type2) { - return (type1.compareTo(zero) > 0); - } - }; - // with thresholds - below thresholds - } else if (tMode == ThresholdMode.Below) { - mandersAccum = new SplitCoeffAccumulator(cursor) { - @Override - final boolean acceptMandersCh1(T type1, T type2) { - return (type2.compareTo(zero) > 0) && - (type2.compareTo(thresholdCh2) <= 0); - } - @Override - final boolean acceptMandersCh2(T type1, T type2) { - return (type1.compareTo(zero) > 0) && - (type1.compareTo(thresholdCh1) <= 0); - } - }; - // with thresholds - above thresholds: tM1 and tM2 - } else if (tMode == ThresholdMode.Above) { - mandersAccum = new SplitCoeffAccumulator(cursor) { - @Override - final boolean acceptMandersCh1(T type1, T type2) { - return (type2.compareTo(zero) > 0) && - (type2.compareTo(thresholdCh2) >= 0); - } - @Override - final boolean acceptMandersCh2(T type1, T type2) { - return (type1.compareTo(zero) > 0) && - (type1.compareTo(thresholdCh1) >= 0); - } - }; - } else { - throw new UnsupportedOperationException(); - } - - MandersResults results = new MandersResults(); - // calculate the results, see description above, as a fraction. - results.m1 = mandersAccum.mandersSumCh1 / mandersAccum.sumCh1; - results.m2 = mandersAccum.mandersSumCh2 / mandersAccum.sumCh2; - - return results; - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - handler.handleValue( "Manders' M1 (Above zero intensity of Ch2)", mandersM1 ); - handler.handleValue( "Manders' M2 (Above zero intensity of Ch1)", mandersM2 ); - handler.handleValue( "Manders' tM1 (Above autothreshold of Ch2)", mandersThresholdedM1 ); - handler.handleValue( "Manders' tM2 (Above autothreshold of Ch1)", mandersThresholdedM2 ); - } - - /** - * A class similar to the Accumulator class, but more specific - * to the Manders' split and other split channel coefficient calculations. - */ - protected abstract class SplitCoeffAccumulator { - double sumCh1, sumCh2, mandersSumCh1, mandersSumCh2; - - public SplitCoeffAccumulator(TwinCursor cursor) { - while (cursor.hasNext()) { - cursor.fwd(); - T type1 = cursor.getFirst(); - T type2 = cursor.getSecond(); - double ch1 = type1.getRealDouble(); - double ch2 = type2.getRealDouble(); - - // boolean logics for adding or not adding to the different value counters for a pixel. - if (acceptMandersCh1(type1, type2)) - mandersSumCh1 += ch1; - if (acceptMandersCh2(type1, type2)) - mandersSumCh2 += ch2; - - // add this pixel's two intensity values to the ch1 and ch2 sum counters - sumCh1 += ch1; - sumCh2 += ch2; - } - } - abstract boolean acceptMandersCh1(T type1, T type2); - abstract boolean acceptMandersCh2(T type1, T type2); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/MissingPreconditionException.java b/src/main/java/sc/fiji/coloc/algorithms/MissingPreconditionException.java deleted file mode 100644 index 4e2c457..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/MissingPreconditionException.java +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * An exception class for missing preconditions for algorithm execution. - */ -public class MissingPreconditionException extends Exception{ - - private static final long serialVersionUID = 1L; - - public MissingPreconditionException() { - super(); - } - - public MissingPreconditionException(String message, Throwable cause) { - super(message, cause); - } - - public MissingPreconditionException(String message) { - super(message); - } - - public MissingPreconditionException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/PearsonsCorrelation.java b/src/main/java/sc/fiji/coloc/algorithms/PearsonsCorrelation.java deleted file mode 100644 index d6398bb..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/PearsonsCorrelation.java +++ /dev/null @@ -1,409 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.MaskFactory; -import sc.fiji.coloc.gadgets.ThresholdMode; -import sc.fiji.coloc.results.ResultHandler; - -/** - * A class that represents the mean calculation of the two source - * images in the data container. - * - * @param - */ -public class PearsonsCorrelation> extends Algorithm { - - // Identifiers for choosing which implementation to use - public enum Implementation {Classic, Fast}; - // The member variable to store the implementation of the Pearson's Coefficient calculation used. - Implementation theImplementation = Implementation.Fast; - // resulting Pearsons value without thresholds - double pearsonsCorrelationValue; - // resulting Pearsons value below threshold - double pearsonsCorrelationValueBelowThr; - // resulting Pearsons value above threshold - double pearsonsCorrelationValueAboveThr; - - /** - * Creates a new Pearson's Correlation and allows us to define - * which implementation of the calculation to use. - * @param implementation The implementation of Pearson's Coefficient calculation to use. - */ - public PearsonsCorrelation(Implementation implementation) { - super("Pearson correlation"); - this.theImplementation = implementation; - } - - /** - * Creates a new Pearson's Correlation with default (fast) implementation parameter. - */ - public PearsonsCorrelation() { - this(Implementation.Fast); - } - - @Override - public void execute(DataContainer container) throws MissingPreconditionException { - // get the 2 images for the calculation of Pearson's - RandomAccessibleInterval img1 = container.getSourceImage1(); - RandomAccessibleInterval img2 = container.getSourceImage2(); - RandomAccessibleInterval mask = container.getMask(); - - // get the thresholds of the images - AutoThresholdRegression autoThreshold = container.getAutoThreshold(); - if (autoThreshold == null ) { - throw new MissingPreconditionException("Pearsons calculation need AutoThresholdRegression to be run before it."); - } - T threshold1 = autoThreshold.getCh1MaxThreshold(); - T threshold2 = autoThreshold.getCh2MaxThreshold(); - if (threshold1 == null || threshold2 == null ) { - throw new MissingPreconditionException("Pearsons calculation needs valid (not null) thresholds."); - } - - /* Create cursors to walk over the images. First go over the - * images without a mask. */ - TwinCursor cursor = new TwinCursor( - img1.randomAccess(), img2.randomAccess(), - Views.iterable(mask).localizingCursor()); - - MissingPreconditionException error = null; - if (theImplementation == Implementation.Classic) { - // get the means from the DataContainer - double ch1Mean = container.getMeanCh1(); - double ch2Mean = container.getMeanCh2(); - - try { - cursor.reset(); - pearsonsCorrelationValue = classicPearsons(cursor, - ch1Mean, ch2Mean); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValue = Double.NaN; - error = e; - } - - try { - cursor.reset(); - pearsonsCorrelationValueBelowThr = classicPearsons(cursor, - ch1Mean, ch2Mean, threshold1, threshold2, ThresholdMode.Below); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValueBelowThr = Double.NaN; - error = e; - } - - try { - cursor.reset(); - pearsonsCorrelationValueAboveThr = classicPearsons(cursor, - ch1Mean, ch2Mean, threshold1, threshold2, ThresholdMode.Above); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValueAboveThr = Double.NaN; - error = e; - } - } - else if (theImplementation == Implementation.Fast) { - try { - cursor.reset(); - pearsonsCorrelationValue = fastPearsons(cursor); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValue = Double.NaN; - error = e; - } - - try { - cursor.reset(); - pearsonsCorrelationValueBelowThr = fastPearsons(cursor, - threshold1, threshold2, ThresholdMode.Below); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValueBelowThr = Double.NaN; - error = e; - } - - try { - cursor.reset(); - pearsonsCorrelationValueAboveThr = fastPearsons(cursor, - threshold1, threshold2, ThresholdMode.Above); - } catch (MissingPreconditionException e) { - // probably a numerical error occurred - pearsonsCorrelationValueAboveThr = Double.NaN; - error = e; - } - } - - // if an error occurred, throw it one level up - if (error != null) - throw error; - } - - /** - * Calculates Pearson's R value without any constraint in values, thus it uses no thresholds. - * If additional data like the images mean is needed, it is calculated. - * - * @param The images base type. - * @param img1 The first image to walk over. - * @param img2 The second image to walk over. - * @return Pearson's R value. - * @throws MissingPreconditionException - */ - public > double calculatePearsons( - RandomAccessibleInterval img1, RandomAccessibleInterval img2) - throws MissingPreconditionException { - // create an "always true" mask to walk over the images - final long[] dims = new long[img1.numDimensions()]; - img1.dimensions(dims); - RandomAccessibleInterval alwaysTrueMask = MaskFactory.createMask(dims, true); - return calculatePearsons(img1, img2, alwaysTrueMask); - } - - /** - * Calculates Pearson's R value without any constraint in values, thus it uses no - * thresholds. A mask is required to mark which data points should be visited. If - * additional data like the images mean is needed, it is calculated. - * - * @param The images base type. - * @param img1 The first image to walk over. - * @param img2 The second image to walk over. - * @param mask A mask for the images. - * @return Pearson's R value. - * @throws MissingPreconditionException - */ - public > double calculatePearsons( - RandomAccessibleInterval img1, RandomAccessibleInterval img2, - RandomAccessibleInterval mask) throws MissingPreconditionException { - TwinCursor cursor = new TwinCursor( - img1.randomAccess(), img2.randomAccess(), - Views.iterable(mask).localizingCursor()); - - double r; - if (theImplementation == Implementation.Classic) { - /* since we need the means and apparently don't have them, - * calculate them. - */ - double mean1 = ImageStatistics.getImageMean(img1); - double mean2 = ImageStatistics.getImageMean(img2); - // do the actual calculation - r = classicPearsons(cursor, mean1, mean2); - } else { - r = fastPearsons(cursor); - } - - return r; - } - - /** - * Calculates Pearson's R value with the possibility to constraint in values. - * This could be useful of one wants to apply thresholds. You need to provide - * the images means, albeit not used by all implementations. - * - * @param The images base type. - * @param cursor The cursor to walk over both images. - * @return Pearson's R value. - * @throws MissingPreconditionException - */ - public > double calculatePearsons(TwinCursor cursor, - double mean1, double mean2, S thresholdCh1, S thresholdCh2, - ThresholdMode tMode) throws MissingPreconditionException { - if (theImplementation == Implementation.Classic) { - // do the actual calculation - return classicPearsons(cursor, mean1, mean2, - thresholdCh1, thresholdCh2, tMode); - } else { - return fastPearsons(cursor, thresholdCh1, - thresholdCh2, tMode); - } - } - - /** - * Calculates Person's R value by using a Classic implementation of the - * algorithm. This method allows the specification of a TwinValueRangeCursor. - * With such a cursor one for instance can combine different thresholding - * conditions for each channel. The cursor is not closed in here. - * - * @param The image base type - * @param cursor The cursor that defines the walk over both images. - * @param meanCh1 Mean of channel 1. - * @param meanCh2 Mean of channel 2. - * @return Person's R value - */ - public static > double classicPearsons(TwinCursor cursor, - double meanCh1, double meanCh2) throws MissingPreconditionException { - return classicPearsons(cursor, meanCh1, meanCh2, null, null, ThresholdMode.None); - } - - public static > double classicPearsons(TwinCursor cursor, - double meanCh1, double meanCh2, final T thresholdCh1, final T thresholdCh2, - ThresholdMode tMode) throws MissingPreconditionException { - // the actual accumulation of the image values is done in a separate object - Accumulator acc; - - if (tMode == ThresholdMode.None) { - acc = new Accumulator(cursor, meanCh1, meanCh2) { - @Override - final public boolean accept(T type1, T type2) { - return true; - } - }; - } else if (tMode == ThresholdMode.Below) { - acc = new Accumulator(cursor, meanCh1, meanCh2) { - @Override - final public boolean accept(T type1, T type2) { - return type1.compareTo(thresholdCh1) < 0 || - type2.compareTo(thresholdCh2) < 0; - } - }; - } else if (tMode == ThresholdMode.Above) { - acc = new Accumulator(cursor, meanCh1, meanCh2) { - @Override - final public boolean accept(T type1, T type2) { - return type1.compareTo(thresholdCh1) > 0 || - type2.compareTo(thresholdCh2) > 0; - } - }; - } else { - throw new UnsupportedOperationException(); - } - - double pearsonsR = acc.xy / Math.sqrt(acc.xx * acc.yy); - - checkForSanity(pearsonsR, acc.count); - return pearsonsR; - } - - /** - * Calculates Person's R value by using a fast implementation of the - * algorithm. This method allows the specification of a TwinValueRangeCursor. - * With such a cursor one for instance can combine different thresholding - * conditions for each channel. The cursor is not closed in here. - * - * @param The image base type - * @param cursor The cursor that defines the walk over both images. - * @return Person's R value - */ - public static > double fastPearsons(TwinCursor cursor) - throws MissingPreconditionException { - return fastPearsons(cursor, null, null, ThresholdMode.None); - } - - public static > double fastPearsons(TwinCursor cursor, - final T thresholdCh1, final T thresholdCh2, ThresholdMode tMode) - throws MissingPreconditionException { - // the actual accumulation of the image values is done in a separate object - Accumulator acc; - - if (tMode == ThresholdMode.None) { - acc = new Accumulator(cursor) { - @Override - final public boolean accept(T type1, T type2) { - return true; - } - }; - } else if (tMode == ThresholdMode.Below) { - acc = new Accumulator(cursor) { - @Override - final public boolean accept(T type1, T type2) { - return type1.compareTo(thresholdCh1) < 0 || - type2.compareTo(thresholdCh2) < 0; - } - }; - } else if (tMode == ThresholdMode.Above) { - acc = new Accumulator(cursor) { - @Override - final public boolean accept(T type1, T type2) { - return type1.compareTo(thresholdCh1) > 0 || - type2.compareTo(thresholdCh2) > 0; - } - }; - } else { - throw new UnsupportedOperationException(); - } - - // for faster computation, have the inverse of N available - double invCount = 1.0 / acc.count; - - double pearsons1 = acc.xy - (acc.x * acc.y * invCount); - double pearsons2 = acc.xx - (acc.x * acc.x * invCount); - double pearsons3 = acc.yy - (acc.y * acc.y * invCount); - double pearsonsR = pearsons1 / (Math.sqrt(pearsons2 * pearsons3)); - - checkForSanity(pearsonsR, acc.count); - - return pearsonsR; - } - - /** - * Does a sanity check for calculated Pearsons values. Wrong - * values can happen for fast and classic implementation. - * - * @param val The value to check. - */ - private static void checkForSanity(double value, int iterations) throws MissingPreconditionException { - if ( Double.isNaN(value) || Double.isInfinite(value)) { - /* For the _fast_ implementation this could happen: - * Infinity could happen if only the numerator is 0, i.e.: - * sum1squared == sum1 * sum1 * invN - * and - * sum2squared == sum2 * sum2 * invN - * If the denominator is also zero, one will get NaN, i.e: - * sumProduct1_2 == sum1 * sum2 * invN - * - * For the classic implementation it could happen, too: - * Infinity happens if one channels sum of value-mean-differences - * is zero. If it is negative for one image you will get NaN. - * Additionally, if is zero for both channels at once you - * could get NaN. NaN - */ - throw new MissingPreconditionException("A numerical problem occured: the input data is unsuitable for this algorithm. Possibly too few pixels (in range were: " + iterations + ")."); - } - } - - @Override - public void processResults(ResultHandler handler) { - super.processResults(handler); - - handler.handleValue("Pearson's R value (no threshold)", pearsonsCorrelationValue, 2); - handler.handleValue("Pearson's R value (below threshold)", pearsonsCorrelationValueBelowThr, 2); - handler.handleValue("Pearson's R value (above threshold)", pearsonsCorrelationValueAboveThr, 2); - } - - public double getPearsonsCorrelationValue() { - return pearsonsCorrelationValue; - } - - public double getPearsonsCorrelationBelowThreshold() { - return pearsonsCorrelationValueBelowThr; - } - - public double getPearsonsCorrelationAboveThreshold() { - return pearsonsCorrelationValueAboveThr; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/SimpleStepper.java b/src/main/java/sc/fiji/coloc/algorithms/SimpleStepper.java deleted file mode 100644 index 7b40cdb..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/SimpleStepper.java +++ /dev/null @@ -1,87 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * The simple stepper decrements a start threshold with every update() call. It - * is finished if the update value is not a number, below zero or larger than - * the last value. It also stops if the decremented threshold falls below one. - * - * @author tom - */ -public class SimpleStepper extends Stepper { - double threshold; - double lastThreshold; - double currentValue; - double lastValue; - boolean finished = false; - - /** - * Initialize the simple sequential stepper with a starting threshold. - * - * @param threshold The starting threshold. - */ - public SimpleStepper(double threshold) { - this.threshold = threshold; - this.currentValue = 1.0; - this.lastValue = Double.MAX_VALUE; - } - - /** - * Decrement the threshold if the stepper is not marked as finished. - * Rendering a stepper finished happens if {@code value} is not a number, - * below or equal zero or bigger than the last update value. The same - * thing happens if the internal threshold falls below one. - */ - @Override - public void update(double value) { - if (!finished) { - // Remember current value and store new value - lastValue = this.currentValue; - currentValue = value; - // Decrement threshold - threshold = this.threshold - 1.0; - - // Stop if the threshold was - finished = Double.NaN == value || - threshold < 1 || - value < 0.0001 || - value > lastValue; - } - } - - /** - * Get the current threshold. - */ - @Override - public double getValue() { - return threshold; - } - - /** - * Indicates if the stepper is marked as finished. - */ - @Override - public boolean isFinished() { - return finished; - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/SpearmanRankCorrelation.java b/src/main/java/sc/fiji/coloc/algorithms/SpearmanRankCorrelation.java deleted file mode 100644 index 7970a0c..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/SpearmanRankCorrelation.java +++ /dev/null @@ -1,331 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -import java.util.Arrays; -import java.util.Comparator; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.results.ResultHandler; - -/* -* This code has been heavily adapted from Numerical Recipces: The Art of Scientific Computing. -* 3rd ed., 2007. Other formulations have been gathered from Wolfram's MathWorld: -* http://mathworld.wolfram.com/SpearmanRankCorrelationCoefficient.html -* -* Adapted from code written by Dan White and Tom Kazimiers -* -* @author Leonardo Guizzetti -*/ - - -/** - * This algorithm calculates Spearman's rank correlation coefficient (Spearman's rho) - * - * @param - */ -public class SpearmanRankCorrelation> extends Algorithm { - // the resulting Spearman rho value - double rhoValue; - double tStatisticSpearman; - int dfSpearman; - - // create two paired arrays: one with raw pixel values and one for the corresponding ranks - double[][] data; - double[] ch1raw; - double[] ch2raw; - double[] ch1ranks; - double[] ch2ranks; - - public SpearmanRankCorrelation() { - super("Spearman's Rank Corelation calculation"); - } - - @Override - public void execute(DataContainer container) - throws MissingPreconditionException { - - // get the 2 images for the calculation of Spearman's rho - RandomAccessibleInterval img1 = container.getSourceImage1(); - RandomAccessibleInterval img2 = container.getSourceImage2(); - RandomAccessibleInterval mask = container.getMask(); - - TwinCursor cursor = new TwinCursor(img1.randomAccess(), - img2.randomAccess(), Views.iterable(mask).localizingCursor()); - // calculate Spearman's rho value - rhoValue = calculateSpearmanRank(cursor); - } - - /** - * Calculates Spearman's Rank Correlation Coefficient (Spearman's rho) for - * two images. - * - * @param cursor A TwinCursor that iterates over two images - * @return Spearman's rank correlation coefficient (rho) value - */ - public > double calculateSpearmanRank(TwinCursor cursor) { - - // Step 0: Count the pixels first. - int n = 0; - while (cursor.hasNext()) { - n++; - cursor.fwd(); - } - cursor.reset(); - - data = new double[n][2]; - - for (int i = 0; i < n; i++) { - cursor.fwd(); - T type1 = cursor.getFirst(); - T type2 = cursor.getSecond(); - data[i][0] = type1.getRealDouble(); - data[i][1] = type2.getRealDouble(); - } - - return calculateSpearmanRank(data); - } - - /** - * Calculates Spearman's Rank Correlation Coefficient (Spearman's rho) for - * two images. - * - * @param data A 2D array containing the data to be ranked - * @return Spearman's rank correlation coefficient (rho) value - */ - public double calculateSpearmanRank(double[][] data) { - final int n = data.length; - ch1raw = new double[n]; - ch2raw = new double[n]; - ch1ranks = new double[n]; - ch2ranks = new double[n]; - - /** - * Here's the concept. Rank-transform the data, then run - * the Pearson correlation on the transformed data. - * - * 1) We will sort the dataset by one column, extract the - * column values and rank them, and replace the data by - * the ranks. - * 2) Repeat the process now with the remaining column. - * 3) Calculate the coefficient from the individual rank - * columns, the t-statistic and the df's of the test. - */ - - // Step 1: Sort the raw data, by column #2 (arbitrary choice). - Arrays.sort(data, new Comparator() { - @Override - public int compare(double[] row1, double[] row2) { - return Double.compare(row1[1], row2[1]); - } - }); - - for (int i = 0; i < n; i++) { - ch2raw[i] = data[i][1]; - } - - // Rank the data then replace them into the dataset. - ch2ranks = rankValues(ch2raw); - for (int i = 0; i < n; i++) { - data[i][1] = ch2ranks[i]; - } - - // Step 2: Repeat step 1 with the other data column. - Arrays.sort(data, new Comparator() { - @Override - public int compare(double[] row1, double[] row2) { - return Double.compare(row1[0], row2[0]); - } - }); - - for (int i = 0; i < n; i++) { - ch1raw[i] = data[i][0]; - } - - ch1ranks = rankValues(ch1raw); - for (int i = 0; i < n; i++) { - data[i][0] = ch1ranks[i]; - ch2ranks[i] = data[i][1]; - } - - // Step 3: Compute statistics. - rhoValue = calculateRho(ch1ranks, ch2ranks); - tStatisticSpearman = getTStatistic(rhoValue, n); - dfSpearman = getSpearmanDF(n); - - return rhoValue; - } - - /** - * Returns degrees of freedom for Spearman's rank correlation. - * - * @param n - N (number of data pairs) - * @return Spearman's rank degrees of freedom. - */ - public int getSpearmanDF(int n) { - return n - 2; - } - - /** - * Returns associated T-Statistic for Spearman's rank correlation. - * - * @param rho - Spearman's rho - * @param n - N (number of data pairs) - * @return Spearman's rank correlation t-statistic - */ - public double getTStatistic(double rho, int n) { - double rho_squared = rho * rho; - return rho * Math.sqrt( (n - 2) / (1 - rho_squared) ); - } - - /** - * Returns sorted rankings for a list of sorted values. - * - * @param sortedVals - The sorted absolute values - * @return ranked sorted list of values - */ - public double[] rankValues(double[] sortedVals) { - - int len = sortedVals.length; - int start = 0; - int end = 0; - double[] newranks = new double[len]; - double avg = 0, ranksum = 0; - boolean ties_found = false; - - // first assign ranks, ascending from 1 - for (int i=0; i handler) { - super.processResults(handler); - handler.handleValue("Spearman's rank correlation value", rhoValue, 8); - handler.handleValue("Spearman's correlation t-statistic", tStatisticSpearman, 4); - handler.handleValue("t-statistic degrees of freedom", dfSpearman); - } -} diff --git a/src/main/java/sc/fiji/coloc/algorithms/Stepper.java b/src/main/java/sc/fiji/coloc/algorithms/Stepper.java deleted file mode 100644 index 16e5864..0000000 --- a/src/main/java/sc/fiji/coloc/algorithms/Stepper.java +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.algorithms; - -/** - * A stepper is used to change some value with every update() call. It should - * finish at some point in time. - * - * @author Tom Kazimiers - */ -public abstract class Stepper { - public abstract void update(double value); - public abstract double getValue(); - public abstract boolean isFinished(); -} diff --git a/src/main/java/sc/fiji/coloc/gadgets/DataContainer.java b/src/main/java/sc/fiji/coloc/gadgets/DataContainer.java deleted file mode 100644 index 6fda1cf..0000000 --- a/src/main/java/sc/fiji/coloc/gadgets/DataContainer.java +++ /dev/null @@ -1,390 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.gadgets; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; - -import sc.fiji.coloc.algorithms.Algorithm; -import sc.fiji.coloc.algorithms.AutoThresholdRegression; -import sc.fiji.coloc.algorithms.InputCheck; -import sc.fiji.coloc.algorithms.MissingPreconditionException; - -/** - * The DataContainer keeps all the source data, jobName, pre-processing results - * and algorithm results that have been computed. It allows a - * ResultsHandler implementation to get most of its content - * and makes the source image and channel information available - * to a client. - * - * @param - */ -public class DataContainer> { - // enumeration of different mask types, include labels - public enum MaskType { - Regular("ROI"), - Irregular("mask image"), - None("none"); - - private final String label; - - MaskType(String label) { - this.label = label; - } - - public String label() { - return label; - } - } - // some general image statistics - private double meanCh1, meanCh2, minCh1, maxCh1, minCh2, maxCh2, integralCh1, integralCh2; - // The source images that the results are based on - private RandomAccessibleInterval sourceImage1, sourceImage2; - // The names of the two source images - private String sourceImage1Name, sourceImage2Name; - // The name of the colocalisation run job - public String jobName; - // The mask for the images - private RandomAccessibleInterval mask; - // Type of the used mask - protected MaskType maskType; - // the hash code integer of the mask object - private int maskHash; - // The channels of the source images that the result relate to - private int ch1, ch2; - // The mask's bounding box - protected long[] maskBBSize = null; - protected long[] maskBBOffset = null; - - InputCheck inputCheck = null; - AutoThresholdRegression autoThreshold = null; - - // a list that contains all added algorithms - List< Algorithm > algorithms = new ArrayList< Algorithm >(); - - /** - * Creates a new {@link DataContainer} for a specific image channel - * combination. We create default thresholds here that are the max and min of - * the data type of the source image channels. - * - * @param src1 The channel one image source - * @param src2 The channel two image source - * @param ch1 The channel one image channel - * @param ch2 The channel two image channel - */ - public DataContainer(RandomAccessibleInterval src1, - RandomAccessibleInterval src2, int ch1, int ch2, - String name1, String name2) { - sourceImage1 = src1; - sourceImage2 = src2; - sourceImage1Name = name1; - sourceImage2Name = name2; - - // create a mask that is true at all pixels. - final long[] dims = new long[src1.numDimensions()]; - src1.dimensions(dims); - mask = MaskFactory.createMask(dims, true); - this.ch1 = ch1; - this.ch2 = ch2; - // fill mask dimension information, here the whole image - maskBBOffset = new long[mask.numDimensions()]; - Arrays.fill(maskBBOffset, 0); - maskBBSize = new long[mask.numDimensions()]; - mask.dimensions(maskBBSize); - // indicated that there is actually no mask - maskType = MaskType.None; - - maskHash = mask.hashCode(); - // create a jobName so ResultHandler instances can all use the same object - // for the job name. - jobName = "Colocalization_of_" + sourceImage1Name + "_versus_" + sourceImage2Name + "_" + maskHash; - - calculateStatistics(); - } - - /** - * Creates a new {@link DataContainer} for a specific set of image and - * channel combination. It will give access to the image according to - * the mask passed. It is expected that the mask is of the same size - * as an image slice. Default thresholds, min, max and mean will be set - * according to the mask as well. - * - * @param src1 The channel one image source - * @param src2 The channel two image source - * @param ch1 The channel one image channel - * @param ch2 The channel two image channel - * @param mask The mask to use - * @param offset The offset of the ROI in each dimension - * @param size The size of the ROI in each dimension - * @throws MissingPreconditionException - */ - public DataContainer(RandomAccessibleInterval src1, - RandomAccessibleInterval src2, int ch1, int ch2, - String name1, String name2, - final RandomAccessibleInterval mask, - final long[] offset, final long[] size) - throws MissingPreconditionException { - sourceImage1 = src1; - sourceImage2 = src2; - this.ch1 = ch1; - this.ch2 = ch2; - sourceImage1Name = name1; - sourceImage2Name = name2; - - final int numDims = src1.numDimensions(); - maskBBOffset = new long[numDims]; - maskBBSize = new long[numDims]; - final long[] dim = new long[numDims]; - src1.dimensions(dim); - this.mask = MaskFactory.createMask(dim.clone(), mask); - - // this constructor supports irregular masks - maskType = MaskType.Irregular; - adjustRoiOffset(offset, maskBBOffset, dim); - adjustRoiSize(size, maskBBSize, dim, maskBBOffset); - - maskHash = mask.hashCode(); - // create a jobName so ResultHandler instances can all use the same - // object for the job name. - jobName = "Colocalization_of_" + sourceImage1Name + "_versus_" + sourceImage2Name + "_" + maskHash; - - calculateStatistics(); - } - - /** - * Creates a new {@link DataContainer} for a specific set of image and - * channel combination. It will give access to the image according to - * the region of interest (ROI) passed. Default thresholds, min, max and - * mean will be set according to the ROI as well. - * - * @param src1 The channel one image source - * @param src2 The channel two image source - * @param ch1 The channel one image channel - * @param ch2 The channel two image channel - * @param offset The offset of the ROI in each dimension - * @param size The size of the ROI in each dimension - */ - public DataContainer(RandomAccessibleInterval src1, - RandomAccessibleInterval src2, int ch1, int ch2, - String name1, String name2, - final long[] offset, final long size[]) - throws MissingPreconditionException { - sourceImage1 = src1; - sourceImage2 = src2; - sourceImage1Name = name1; - sourceImage2Name = name2; - - final int numDims = src1.numDimensions(); - final long[] dim = new long[numDims]; - src1.dimensions(dim); - long[] roiOffset = new long[numDims]; - long[] roiSize = new long[numDims]; - - adjustRoiOffset(offset, roiOffset, dim); - adjustRoiSize(size, roiSize, dim, roiOffset); - - // create a mask that is valid everywhere - mask = MaskFactory.createMask(dim, roiOffset, roiSize); - maskBBOffset = roiOffset.clone(); - maskBBSize = roiSize.clone(); - // this constructor only supports regular masks - maskType = MaskType.Regular; - - this.ch1 = ch1; - this.ch2 = ch2; - - maskHash = mask.hashCode(); - // create a jobName so ResultHandler instances can all use the same - // object for the job name. - jobName = "Colocalization_of_" + sourceImage1Name + "_versus_" + sourceImage2Name + "_" + maskHash; - - calculateStatistics(); - } - - protected void calculateStatistics() { - meanCh1 = ImageStatistics.getImageMean(sourceImage1, mask); - meanCh2 = ImageStatistics.getImageMean(sourceImage2, mask); - minCh1 = ImageStatistics.getImageMin(sourceImage1, mask).getRealDouble(); - minCh2 = ImageStatistics.getImageMin(sourceImage2, mask).getRealDouble(); - maxCh1 = ImageStatistics.getImageMax(sourceImage1, mask).getRealDouble(); - maxCh2 = ImageStatistics.getImageMax(sourceImage2, mask).getRealDouble(); - integralCh1 = ImageStatistics.getImageIntegral(sourceImage1, mask); - integralCh2 = ImageStatistics.getImageIntegral(sourceImage2, mask); - } - - /** - * Make sure that the ROI offset has the same dimensionality - * as the image. The method fills it up with zeros if needed. - * - * @param oldOffset The offset with the original dimensionality - * @param newOffset The output array with the new dimensionality - * @param dimensions An array of the dimensions - * @throws MissingPreconditionException - */ - protected void adjustRoiOffset(long[] oldOffset, long[] newOffset, long[] dimensions) - throws MissingPreconditionException { - for (int i=0; i dimensions[i]) - throw new MissingPreconditionException("Dimension " + i + " of ROI offset is larger than image dimension."); - newOffset[i] = oldOffset[i]; - } else { - newOffset[i] = 0; - } - } - } - - /** - * Transforms a ROI size array to a dimensionality. The method - * fill up with image (dimension - offset in that dimension) if - * needed. - * - * @param oldSize Size array of old dimensionality - * @param newSize Output size array of new dimensionality - * @param dimensions Dimensions representing the new dimensionality - * @param offset Offset of the new dimensionality - * @throws MissingPreconditionException - */ - protected void adjustRoiSize(long[] oldSize, long[] newSize, long[] dimensions, long[] offset) - throws MissingPreconditionException { - for (int i=0; i (dimensions[i] - offset[i])) - throw new MissingPreconditionException("Dimension " + i + " of ROI size is larger than what fits in."); - newSize[i] = oldSize[i]; - } else { - newSize[i] = dimensions[i] - offset[i]; - } - } - } - - public RandomAccessibleInterval getSourceImage1() { - return sourceImage1; - } - - public RandomAccessibleInterval getSourceImage2() { - return sourceImage2; - } - - public String getSourceImage1Name() { - return "Ch1_" + sourceImage1Name; - } - - public String getSourceImage2Name() { - return "Ch2_" + sourceImage2Name; - } - - public String getSourceCh1Name() { - return sourceImage1Name; - } - - public String getSourceCh2Name() { - return sourceImage2Name; - } - - public String getJobName() { - return jobName; - } - - public RandomAccessibleInterval getMask() { - return mask; - } - - public long[] getMaskBBOffset() { - return maskBBOffset.clone(); - } - - public long[] getMaskBBSize() { - return maskBBSize.clone(); - } - - public MaskType getMaskType(){ - return maskType; - } - - public int getMaskID(){ - return maskHash; - } - - public int getCh1() { - return ch1; - } - - public int getCh2() { - return ch2; - } - public double getMeanCh1() { - return meanCh1; - } - - public double getMeanCh2() { - return meanCh2; - } - - public double getMinCh1() { - return minCh1; - } - - public double getMaxCh1() { - return maxCh1; - } - - public double getMinCh2() { - return minCh2; - } - - public double getMaxCh2() { - return maxCh2; - } - - public double getIntegralCh1() { - return integralCh1; - } - - public double getIntegralCh2() { - return integralCh2; - } - - public InputCheck getInputCheck() { - return inputCheck; - } - - public Algorithm setInputCheck(InputCheck inputCheck) { - this.inputCheck = inputCheck; - return inputCheck; - } - - public AutoThresholdRegression getAutoThreshold() { - return autoThreshold; - } - - public Algorithm setAutoThreshold(AutoThresholdRegression autoThreshold) { - this.autoThreshold = autoThreshold; - return autoThreshold; - } -} diff --git a/src/main/java/sc/fiji/coloc/gadgets/MaskFactory.java b/src/main/java/sc/fiji/coloc/gadgets/MaskFactory.java deleted file mode 100644 index 3d25032..0000000 --- a/src/main/java/sc/fiji/coloc/gadgets/MaskFactory.java +++ /dev/null @@ -1,214 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.gadgets; - -import java.util.Arrays; - -import net.imglib2.Cursor; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.algorithms.MissingPreconditionException; - -public class MaskFactory { - - public enum CombinationMode { - AND, OR, NONE - } - - /** - * Create a new mask image without any specific content, but with - * a defined size. - */ - public static RandomAccessibleInterval createMask(long[] dim) { - ImgFactory< BitType > imgFactory = new ArrayImgFactory< BitType >(); - return imgFactory.create(dim, new BitType()); - } - - /** - * Create a new mask image with a defined size and preset content. - */ - public static RandomAccessibleInterval createMask(long[] dim, boolean val) { - RandomAccessibleInterval mask = createMask(dim); - - for (BitType t : Views.iterable(mask)) - t.set(val); - - return mask; - } - - /** - * Create a new mask image with a defined size and preset content. - * @throws MissingPreconditionException - */ - public static RandomAccessibleInterval createMask(long[] dim, long[] roiOffset, long[] roiDim) - throws MissingPreconditionException { - if (dim.length != roiOffset.length || dim.length != roiDim.length) { - throw new MissingPreconditionException("The dimensions of the mask as well as the ROIs and his offset must be the same."); - } - - final RandomAccessibleInterval mask = createMask(dim); - final int dims = mask.numDimensions(); - final long[] pos = new long[dims]; - - - // create an array with the max corner of the ROI - final long[] roiOffsetMax = new long[dims]; - for (int i=0; i cursor = Views.iterable(mask).localizingCursor(); - while ( cursor.hasNext() ) { - cursor.fwd(); - cursor.localize(pos); - boolean valid = true; - // test if the current position is contained in the ROI - for(int i=0; i= roiOffset[i] && pos[i] < roiOffsetMax[i]; - cursor.get().set(valid); - } - - return mask; - } - - /** - * Create a new mask based on a threshold condition for two images. - */ - public static> RandomAccessibleInterval createMask( - RandomAccessibleInterval ch1, RandomAccessibleInterval ch2, - T threshold1, T threshold2, ThresholdMode tMode, CombinationMode cMode) { - - final long[] dims = new long[ ch1.numDimensions() ]; - ch1.dimensions(dims); - RandomAccessibleInterval mask = createMask(dims); - Cursor cursor1 = Views.iterable(ch1).cursor(); - Cursor cursor2 = Views.iterable(ch2).cursor(); - Cursor maskCursor = Views.iterable(mask).cursor(); - - while (cursor1.hasNext() && cursor2.hasNext() && maskCursor.hasNext()) { - cursor1.fwd(); - cursor2.fwd(); - maskCursor.fwd(); - - boolean ch1Valid, ch2Valid; - - T data1 = cursor1.get(); - T data2 = cursor2.get(); - - // get relation to threshold - if (tMode == ThresholdMode.Above) { - ch1Valid = data1.compareTo(threshold1) > 0; - ch2Valid = data2.compareTo(threshold2) > 0; - } else if (tMode == ThresholdMode.Below) { - ch1Valid = data1.compareTo(threshold1) < 0; - ch2Valid = data2.compareTo(threshold2) < 0; - } else { - throw new UnsupportedOperationException(); - } - - BitType maskData = maskCursor.get(); - - // combine the results into mask - if (cMode == CombinationMode.AND) { - maskData.set( ch1Valid && ch2Valid ); - } else if (cMode == CombinationMode.OR) { - maskData.set( ch1Valid || ch2Valid ); - } else if (cMode == CombinationMode.NONE) { - maskData.set( !(ch1Valid || ch2Valid) ); - } else { - throw new UnsupportedOperationException(); - } - } - - return mask; - } - - /** - * Creates a new mask of the given dimensions, based on the image data - * in the passed image. If the requested dimensionality is higher than - * what is available in the data, the data gets repeated in the higher - * dimensions. - * - * @param dim The dimensions of the new mask image - * @param origMask The image from which the mask should be created from - */ - public static> RandomAccessibleInterval createMask( - final long[] dim, final RandomAccessibleInterval origMask) { - final RandomAccessibleInterval mask = createMask(dim); - final long[] origDim = new long[ origMask.numDimensions() ]; - origMask.dimensions(origDim); - - // test if original mask and new mask have same dimensions - if (Arrays.equals(dim, origDim)) { - // copy the input image to the mask output image - Cursor origCursor = Views.iterable(origMask).localizingCursor(); - RandomAccess maskCursor = mask.randomAccess(); - while (origCursor.hasNext()) { - origCursor.fwd(); - maskCursor.setPosition(origCursor); - boolean value = origCursor.get().getRealDouble() > 0.001; - maskCursor.get().set(value); - } - } else if (dim.length > origDim.length) { - // sanity check - for (int i=0; i origCursor = Views.iterable(origMask).localizingCursor(); - RandomAccess maskCursor = mask.randomAccess(); - final long[] pos = new long[ origMask.numDimensions() ]; - // iterate over the original mask - while (origCursor.hasNext()) { - origCursor.fwd(); - origCursor.localize(pos); - boolean value = origCursor.get().getRealDouble() > 0.001; - // set available (lower dimensional) position information - for (int i=0; i. - * #L% - */ -package sc.fiji.coloc.gadgets; - -import java.util.List; - -/** - * This class provides some basic statistics methods. - * - * @author Tom Kazimiers - * - */ -public class Statistics { - - // have the inverted square root of two ready to use - static final double invSqrtTwo = 1.0 / Math.sqrt(2); - - /** - * Calculates an estimate of the upper tail cumulative normal distribution - * (which is simply the complementary error function with linear scalings - * of x and y axis). - * - * Fractional error in math formula less than 1.2 * 10 ^ -7. - * although subject to catastrophic cancellation when z in very close to 0 - * - * Code from (thanks to Bob Dougherty): - * w - * - * Original algorithm from Section 6.2 of Numerical Recipes - */ - public static double erf(double z) { - double t = 1.0 / (1.0 + 0.5 * Math.abs(z)); - - // use Horner's method - double ans = 1 - t * Math.exp( -z*z - 1.26551223 + - t * ( 1.00002368 + - t * ( 0.37409196 + - t * ( 0.09678418 + - t * (-0.18628806 + - t * ( 0.27886807 + - t * (-1.13520398 + - t * ( 1.48851587 + - t * (-0.82215223 + - t * ( 0.17087277)))))))))); - if (z >= 0) - return ans; - else - return -ans; - } - - /** - * Calculates phi, which is the area of the Gaussian standard - * distribution from minus infinity to the query value in units - * of standard derivation. - * The formula is: - * - * 1 + erf( z / sqrt(2) ) - * Phi(z) = ---------------------- - * 2 - * @param z The point of interest - * @return phi - */ - public static double phi(double z) { - return 0.5 * (1.0 + erf( z * invSqrtTwo ) ); - } - - /** - * Calculates phi, but with a Gaussian distribution defined by - * its mean and its standard derivation. This is a quantile. - * - * 1 + erf( (z - mean) / (sqrt(2) * stdDev) ) - * Phi(z,mean,stdDev) = ------------------------------------------ - * 2 * - * @param z The point of interest - * @param mean The mean of the distribution - * @param sd The standard derivation of the distribution - * @return phi - */ - public static double phi(double z, double mean, double sd) { - return phi( (z - mean) / sd); - } - - /** - * Calculates the standard deviation of a list of values. - * - * @param values The list of values. - * @return The standard deviation. - */ - public static double stdDeviation(List values) { - int count = values.size(); - // calculate mean - double sum = 0; - for( Double val : values ) { - sum += val; - } - double mean = sum / count; - - // calculate deviates - sum = 0; - for( Double val : values ) { - double diff = val - mean; - double sqDiff = diff * diff; - sum += sqDiff; - } - double stdDeviation = Math.sqrt( sum / (count - 1) ); - - return stdDeviation; - } -} diff --git a/src/main/java/sc/fiji/coloc/gadgets/ThresholdMode.java b/src/main/java/sc/fiji/coloc/gadgets/ThresholdMode.java deleted file mode 100644 index b2a923b..0000000 --- a/src/main/java/sc/fiji/coloc/gadgets/ThresholdMode.java +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.gadgets; - -/** - * An enumerator for different modes of threshold handling. - */ -public enum ThresholdMode { - Below, Above, None -} diff --git a/src/main/java/sc/fiji/coloc/results/AnalysisResults.java b/src/main/java/sc/fiji/coloc/results/AnalysisResults.java deleted file mode 100644 index 4baf757..0000000 --- a/src/main/java/sc/fiji/coloc/results/AnalysisResults.java +++ /dev/null @@ -1,114 +0,0 @@ - -package sc.fiji.coloc.results; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.LongType; - -import sc.fiji.coloc.algorithms.Histogram2D; - -/** - * Data structure housing all colocalisation results. Intended for programmatic - * access via API calls. - * - * @author Curtis Rueden - */ -public class AnalysisResults> implements - ResultHandler -{ - - /** Result images, no matter what specific kinds. */ - private final List>>> listOfImages = - new ArrayList<>(); - - /** Histogram results. */ - private final Map, Histogram2D> mapOf2DHistograms = - new HashMap<>(); - - /** Warnings produced during analysis. */ - private final List warnings = new ArrayList<>(); - - /** Named values, collected from algorithms. */ - private final List valueResults = new ArrayList<>(); - - /** - * Images and corresponding LUTs. When an image is not in there no LUT should - * be applied. - */ - private final Map listOfLUTs = new HashMap<>(); - - // -- AllTheData methods -- - - public List>>> - images() - { - return listOfImages; - } - - public Map, Histogram2D> histograms() { - return mapOf2DHistograms; - } - - public List warnings() { - return warnings; - } - - public List values() { - return valueResults; - } - - // -- ResultHandler methods -- - - @Override - public void handleImage(final RandomAccessibleInterval image, - final String name) - { - listOfImages.add( - new NamedContainer>>(image, - name)); - } - - @Override - public void handleHistogram(final Histogram2D histogram, - final String name) - { - listOfImages.add( - new NamedContainer>>( - histogram.getPlotImage(), name)); - mapOf2DHistograms.put(histogram.getPlotImage(), histogram); - // link the histogram to a LUT - listOfLUTs.put(histogram.getPlotImage(), "Fire"); - } - - @Override - public void handleWarning(final Warning warning) { - warnings.add(warning); - } - - @Override - public void handleValue(final String name, final String value) { - valueResults.add(new ValueResult(name, value)); - } - - @Override - public void handleValue(final String name, final double value) { - handleValue(name, value, 3); - } - - @Override - public void handleValue(final String name, final double value, - final int decimals) - { - valueResults.add(new ValueResult(name, value, decimals)); - } - - @Override - public void process() { - // NB: No action needed. - } -} diff --git a/src/main/java/sc/fiji/coloc/results/EasyDisplay.java b/src/main/java/sc/fiji/coloc/results/EasyDisplay.java deleted file mode 100644 index 977ce60..0000000 --- a/src/main/java/sc/fiji/coloc/results/EasyDisplay.java +++ /dev/null @@ -1,119 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -import ij.IJ; -import ij.ImagePlus; -import ij.text.TextWindow; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.type.numeric.RealType; - -import sc.fiji.coloc.algorithms.Histogram2D; -import sc.fiji.coloc.gadgets.DataContainer; - -public class EasyDisplay> implements ResultHandler { - // the text window to present value and text results - protected static TextWindow textWindow; - /* the data container with general information about the - * source images that were processed by the algorithms. - */ - protected DataContainer container; - - public EasyDisplay(DataContainer container) { - final int twWidth = 170; - final int twHeight = 250; - //test if the results windows is already there, if so use it. - if (textWindow == null || !textWindow.isVisible()) - textWindow = new TextWindow("Results", - "Result\tValue\n", "", twWidth, twHeight); - else { - // set dimensions - textWindow.setSize(twWidth, twHeight); - } - // deactivate the window for now - textWindow.setVisible(false); - // save a reference to the data container - this.container = container; - } - - @Override - public void handleImage(RandomAccessibleInterval image, String name) { - ImagePlus imp = ImageJFunctions.wrapFloat( image, name ); - double max = ImageStatistics.getImageMax( image ).getRealDouble(); - showImage( imp, max ); - } - - @Override - public void handleHistogram(Histogram2D histogram, String name) { - ImagePlus imp = ImageJFunctions.wrapFloat( histogram.getPlotImage(), name ); - double max = ImageStatistics.getImageMax( histogram.getPlotImage() ).getRealDouble(); - showImage( imp, max ); - } - - protected void showImage(ImagePlus imp, double max) { - // set the display range - imp.setDisplayRange(0.0, max); - imp.show(); - } - - @Override - public void handleWarning(Warning warning) { - // no warnings are shown in easy display - } - - @Override - public void handleValue(String name, String value) { - textWindow.getTextPanel().appendLine(name + "\t" - + value + "\n"); - } - - @Override - public void handleValue(String name, double value) { - handleValue(name, value, 3); - } - - @Override - public void handleValue(String name, double value, int decimals) { - handleValue(name, IJ.d2s(value, decimals)); - } - - protected void printTextStatistics(DataContainer container){ - textWindow.getTextPanel().appendLine("Ch1 Mean\t" + container.getMeanCh1() + "\n"); - textWindow.getTextPanel().appendLine("Ch2 Mean\t" + container.getMeanCh2() + "\n"); - textWindow.getTextPanel().appendLine("Ch1 Min\t" + container.getMinCh1() + "\n"); - textWindow.getTextPanel().appendLine("Ch2 Min\t" + container.getMinCh2() + "\n"); - textWindow.getTextPanel().appendLine("Ch1 Max\t" + container.getMaxCh1() + "\n"); - textWindow.getTextPanel().appendLine("Ch2 Max\t" + container.getMaxCh2() + "\n"); - } - - @Override - public void process() { - // print some general information about images - printTextStatistics(container); - // show the results - textWindow.setVisible(true); - IJ.selectWindow("Results"); - } -} diff --git a/src/main/java/sc/fiji/coloc/results/NamedContainer.java b/src/main/java/sc/fiji/coloc/results/NamedContainer.java deleted file mode 100644 index 730d699..0000000 --- a/src/main/java/sc/fiji/coloc/results/NamedContainer.java +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -/** - * A small container to name objects by overriding - * the toString method. - * - */ -public class NamedContainer { - T object; - String name; - - public NamedContainer(T object, String name) { - this.object = object; - this.name = name; - } - - public T getObject() { - return object; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/sc/fiji/coloc/results/PDFWriter.java b/src/main/java/sc/fiji/coloc/results/PDFWriter.java deleted file mode 100644 index a434b2f..0000000 --- a/src/main/java/sc/fiji/coloc/results/PDFWriter.java +++ /dev/null @@ -1,260 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -import com.itextpdf.text.BadElementException; -import com.itextpdf.text.Document; -import com.itextpdf.text.DocumentException; -import com.itextpdf.text.PageSize; -import com.itextpdf.text.Paragraph; -import com.itextpdf.text.pdf.PdfContentByte; -import com.itextpdf.text.pdf.PdfWriter; - -import ij.IJ; -import ij.ImagePlus; -import ij.io.SaveDialog; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.LongType; - -import sc.fiji.coloc.algorithms.Histogram2D; -import sc.fiji.coloc.gadgets.DataContainer; -import sc.fiji.coloc.gadgets.DataContainer.MaskType; - - -public class PDFWriter> implements ResultHandler { - - // indicates if we want to produce US letter or A4 size - boolean isLetter = false; - // indicates if the content is the first item on the page - boolean isFirst = true; - // show the name of the image - static boolean showName=true; - // a static counter for this sessions created PDFs - static int succeededPrints = 0; - // show the size in pixels of the image - static boolean showSize=true; - // a reference to the data container - DataContainer container; - PdfWriter writer; - Document document; - - // a list of the available result images, no matter what specific kinds - protected List listOfPDFImages - = new ArrayList(); - protected List listOfPDFTexts - = new ArrayList(); - // a list of PDF warnings - protected List PDFwarnings = new ArrayList(); - - /** - * Creates a new PDFWriter that can access the container. - * - * @param container The data container for source image data - */ - public PDFWriter(DataContainer container) { - this.container = container; - } - - @Override - public void handleImage(RandomAccessibleInterval image, String name) { - ImagePlus imp = ImageJFunctions.wrapFloat( image, name ); - - // set the display range - double max = ImageStatistics.getImageMax(image).getRealDouble(); - imp.setDisplayRange(0.0, max); - addImageToList(imp, name); - } - - /** - * Handles a histogram the following way: create snapshot, log data, reset the - * display range, apply the Fire LUT and finally store it as an iText PDF image. - * Afterwards the image is reset to its orignal state again - */ - @Override - public void handleHistogram(Histogram2D histogram, String name) { - RandomAccessibleInterval image = histogram.getPlotImage(); - ImagePlus imp = ImageJFunctions.wrapFloat( image, name ); - // make a snapshot to be able to reset after modifications - imp.getProcessor().snapshot(); - imp.getProcessor().log(); - imp.updateAndDraw(); - imp.getProcessor().resetMinAndMax(); - IJ.run(imp,"Fire", null); - addImageToList(imp, name); - // reset the imp from the log scaling we applied earlier - imp.getProcessor().reset(); - } - - protected void addImageToList(ImagePlus imp, String name) { - java.awt.Image awtImage = imp.getImage(); - try { - com.itextpdf.text.Image pdfImage = com.itextpdf.text.Image.getInstance(awtImage, null); - pdfImage.setAlt(name); // iText-1.3 setMarkupAttribute("name", name); - listOfPDFImages.add(pdfImage); - } - catch (BadElementException e) { - IJ.log("Could not convert image to correct format for PDF generation"); - IJ.handleException(e); - } - catch (IOException e) { - IJ.log("Could not convert image to correct format for PDF generation"); - IJ.handleException(e); - } - } - - @Override - public void handleWarning(Warning warning) { - PDFwarnings.add(new Paragraph("Warning! " + warning.getShortMessage() + " - " + warning.getLongMessage())); - } - - @Override - public void handleValue(String name, String value) { - listOfPDFTexts.add(new Paragraph(name + ": " + value)); - } - - @Override - public void handleValue(String name, double value) { - handleValue(name, value, 3); - } - - @Override - public void handleValue(String name, double value, int decimals) { - listOfPDFTexts.add(new Paragraph(name + ": " + IJ.d2s(value, decimals))); - } - - /** - * Prints an image into the opened PDF. - * @param image The image to print. - */ - protected void addImage(com.itextpdf.text.Image image) - throws DocumentException, IOException { - - if (! isFirst) { - document.add(new Paragraph("\n")); - float vertPos = writer.getVerticalPosition(true); - if (vertPos - document.bottom() < image.getHeight()) { - document.newPage(); - } else { - PdfContentByte cb = writer.getDirectContent(); - cb.setLineWidth(1f); - if (isLetter) { - cb.moveTo(PageSize.LETTER.getLeft(50), vertPos); - cb.lineTo(PageSize.LETTER.getRight(50), vertPos); - } else { - cb.moveTo(PageSize.A4.getLeft(50), vertPos); - cb.lineTo(PageSize.A4.getRight(50), vertPos); - } - cb.stroke(); - } - } - - if (showName) { - Paragraph paragraph = new Paragraph(image.getAlt()); // iText-1.3: getMarkupAttribute("name")); - paragraph.setAlignment(Paragraph.ALIGN_CENTER); - document.add(paragraph); - //spcNm = 40; - } - - if (showSize) { - Paragraph paragraph = new Paragraph(image.getWidth() + " x " + image.getHeight()); - paragraph.setAlignment(Paragraph.ALIGN_CENTER); - document.add(paragraph); - //spcSz = 40; - } - - image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER); - document.add(image); - isFirst = false; - } - - @Override - public void process() { - try { - // Use the getJobName() in DataContainer for the job name. - String jobName = container.getJobName(); - - /* If a mask is in use, add a counter - * information to the jobName. - */ - if (container.getMaskType() != MaskType.None) { - // maskHash is now used as the mask or ROI unique ID in the - // jobName but we can still increment and use succeededPrints at - // the end of the filename for PDFs when there is a mask. - jobName += (succeededPrints + 1); - } - // get the path to the file we are about to create - SaveDialog sd = new SaveDialog("Save as PDF", jobName, ".pdf"); - // update jobName if the user changes it in the save file dialog. - jobName = sd.getFileName(); - String directory = sd.getDirectory(); - // make sure we have what we need next - if ((jobName == null) || (directory == null)) { - return; - } - String path = directory+jobName; - // create a new iText Document and add date and title - document = new Document(isLetter ? PageSize.LETTER : PageSize.A4); - document.addCreationDate(); - document.addTitle(jobName); - // get a writer object to do the actual output - writer = PdfWriter.getInstance(document, new FileOutputStream(path)); - document.open(); - - // write job name at the top of the PDF file as a title - Paragraph titlePara = new Paragraph(jobName); - document.add(titlePara); - - // iterate over all produced images - for (com.itextpdf.text.Image img : listOfPDFImages) { - addImage(img); - } - - //iterate over all produced PDFwarnings - for (Paragraph p : PDFwarnings) { - document.add(p); - } - - //iterate over all produced text objects - for (Paragraph p : listOfPDFTexts) { - document.add(p); - } - } catch(DocumentException de) { - IJ.showMessage("PDF Writer", de.getMessage()); - } catch(IOException ioe) { - IJ.showMessage("PDF Writer", ioe.getMessage()); - } finally { - if (document !=null) { - document.close(); - succeededPrints++; - } - } - } -} diff --git a/src/main/java/sc/fiji/coloc/results/ResultHandler.java b/src/main/java/sc/fiji/coloc/results/ResultHandler.java deleted file mode 100644 index ef61582..0000000 --- a/src/main/java/sc/fiji/coloc/results/ResultHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.type.numeric.RealType; - -import sc.fiji.coloc.algorithms.Histogram2D; - -/** - * A result handler offers different methods to process results - * of algorithms. Algorithms get passed such a result handler and - * can let the handler process whatever information they like. - * - * @param The source images value type - */ -public interface ResultHandler> { - - void handleImage(RandomAccessibleInterval image, String name); - - void handleHistogram(Histogram2D histogram, String name); - - void handleWarning(Warning warning); - - void handleValue(String name, String value); - - void handleValue(String name, double value); - - void handleValue(String name, double value, int decimals); - - /** - * The process method should start the processing of the - * previously collected results. E.g. it could show some - * windows or produce a final zip file. - */ - void process(); -} diff --git a/src/main/java/sc/fiji/coloc/results/SingleWindowDisplay.java b/src/main/java/sc/fiji/coloc/results/SingleWindowDisplay.java deleted file mode 100644 index acda598..0000000 --- a/src/main/java/sc/fiji/coloc/results/SingleWindowDisplay.java +++ /dev/null @@ -1,722 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -import ij.IJ; -import ij.ImageJ; -import ij.ImagePlus; -import ij.gui.Line; -import ij.gui.Overlay; -import ij.process.ImageProcessor; -import ij.text.TextWindow; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Panel; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.ClipboardOwner; -import java.awt.datatransfer.StringSelection; -import java.awt.datatransfer.Transferable; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionListener; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JEditorPane; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; - -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.LongType; - -import sc.fiji.coloc.algorithms.AutoThresholdRegression; -import sc.fiji.coloc.algorithms.Histogram2D; -import sc.fiji.coloc.gadgets.DataContainer; - -import fiji.util.gui.JImagePanel; - -/** - * This class displays the container contents in one single window and offers - * features like the use of different LUTs. - * - */ -public class SingleWindowDisplay> extends JFrame - implements ResultHandler, ItemListener, ActionListener, ClipboardOwner, MouseMotionListener { - private static final long serialVersionUID = -5642321584354176878L; - protected static final int WIN_WIDTH = 350; - protected static final int WIN_HEIGHT = 600; - - // indicates if original images should be displayed or not - protected boolean displayOriginalImages = false; - - // this is the image currently selected by the drop down menu - protected RandomAccessibleInterval> currentlyDisplayedImageResult; - - // a list of the available result images, no matter what specific kinds - protected List>>> listOfImages = new ArrayList>>>(); - protected Map, Histogram2D> mapOf2DHistograms = new HashMap, Histogram2D>(); - // a list of warnings - protected List warnings = new ArrayList(); - // a list of named values, collected from algorithms - protected List valueResults = new ArrayList(); - - /* - * a map of images and corresponding LUTs. When an image is not in there no - * LUT should be applied. - */ - protected Map listOfLUTs = new HashMap(); - - // make a cursor so we can get pixel values from the image - protected RandomAccess> pixelAccessCursor; - - // A PDF writer to call if user wants PDF print - protected PDFWriter pdfWriter; - - // The current image - protected ImagePlus imp; - - // GUI elements - protected JImagePanel imagePanel; - protected JButton listButton, copyButton; - protected JCheckBox log; - - /* - * The data container with general information about source images - */ - protected DataContainer dataContainer = null; - - public SingleWindowDisplay(DataContainer container, PDFWriter pdfWriter) { - // Show job name in title bar - super(container.getJobName()); - - setPreferredSize(new Dimension(WIN_WIDTH, WIN_HEIGHT)); - - // save a reference to the container - dataContainer = container; - this.pdfWriter = pdfWriter; - // don't show ourself on instantiation - this.setVisible(false); - } - - public void setup() { - - JComboBox dropDownList = new JComboBox(); - for (NamedContainer>> img : listOfImages) { - dropDownList - .addItem(new NamedContainer>>(img.object, img.name)); - } - dropDownList.addItemListener(this); - - imagePanel = new JImagePanel(ij.IJ.createImage("dummy", "8-bit", 10, 10, 1)); - imagePanel.addMouseMotionListener(this); - - // Create something to display it in - final JEditorPane editor = new JEditorPane(); - editor.setEditable(false); // we're browsing not editing - editor.setContentType("text/html"); // must specify HTML text - editor.setText(makeHtmlText()); // specify the text to display - - // Put the JEditorPane in a scrolling window and add it - JScrollPane scrollPane = new JScrollPane(editor); - scrollPane.setPreferredSize(new Dimension(256, 150)); - - Panel buttons = new Panel(); - buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); - // add button for data display of histograms - listButton = new JButton("List"); - listButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showList(); - } - }); - buttons.add(listButton); - // add button for data copy of histograms - copyButton = new JButton("Copy"); - copyButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - copyToClipboard(); - } - }); - buttons.add(copyButton); - // add button for PDF printing - JButton pdfButten = new JButton("PDF"); - pdfButten.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - pdfWriter.process(); - } - }); - buttons.add(pdfButten); - - /* - * We want the image to be log scale by default so the user can see - * something. - */ - log = new JCheckBox("Log"); - log.setSelected(true); - log.addActionListener(this); - buttons.add(log); - - final GridBagLayout layout = new GridBagLayout(); - final Container pane = getContentPane(); - getContentPane().setLayout(layout); - final GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.weightx = 1; - c.gridwidth = GridBagConstraints.BOTH; - c.gridy++; - pane.add(dropDownList, c); - c.gridy++; - c.weighty = 1; - // code to include axis labels - JPanel imageAndLabelPanel = new JPanel(); - imageAndLabelPanel.setLayout(new BorderLayout()); - imageAndLabelPanel.add(imagePanel, BorderLayout.CENTER); - JLabel yAxisLabel = new JLabel(labelName(2, dataContainer.getSourceCh2Name())); - yAxisLabel.setHorizontalAlignment(SwingConstants.RIGHT); - yAxisLabel.setBorder(new EmptyBorder(0, 15, 0, 0)); - imageAndLabelPanel.add(yAxisLabel, BorderLayout.WEST); - JLabel xAxisLabel = new JLabel(labelName(1, dataContainer.getSourceCh1Name())); - xAxisLabel.setHorizontalAlignment(SwingConstants.CENTER); - xAxisLabel.setBorder(new EmptyBorder(0, 0, 15, 0)); - imageAndLabelPanel.add(xAxisLabel, BorderLayout.SOUTH); - pane.add(imageAndLabelPanel, c); - c.gridy++; - c.weighty = 1; - pane.add(scrollPane, c); - c.weighty = 0; - c.gridy++; - pane.add(buttons, c); - } - - private String labelName(int ch, String s) { - final int maxLen = 30; - final String shortName = s.length() > maxLen ? // - s.substring(0, maxLen - 3) + "..." : s; - return "
Channel " + ch + "
(" + shortName + ")
"; - } - - @Override - public void process() { - // if wanted, display source images - if (displayOriginalImages) { - listOfImages.add(new NamedContainer>>( - dataContainer.getSourceImage1(), dataContainer.getSourceImage1Name())); - listOfImages.add(new NamedContainer>>( - dataContainer.getSourceImage2(), dataContainer.getSourceImage2Name())); - } - - // set up the GUI, which runs makeHtmlText() for the value results - // formatting. - setup(); - // display the first image available, if any - if (listOfImages.size() > 0) { - adjustDisplayedImage(listOfImages.get(0).object); - } - // show the GUI - setSize(600,600); - this.setVisible(true); - } - - @Override - public void handleImage(RandomAccessibleInterval image, String name) { - listOfImages.add(new NamedContainer>>(image, name)); - } - - @Override - public void handleHistogram(Histogram2D histogram, String name) { - listOfImages.add( - new NamedContainer>>(histogram.getPlotImage(), name)); - mapOf2DHistograms.put(histogram.getPlotImage(), histogram); - // link the histogram to a LUT - listOfLUTs.put(histogram.getPlotImage(), "Fire"); - } - - @Override - public void handleWarning(Warning warning) { - warnings.add(warning); - } - - @Override - public void handleValue(String name, String value) { - valueResults.add(new ValueResult(name, value)); - } - - @Override - public void handleValue(String name, double value) { - handleValue(name, value, 3); - } - - @Override - public void handleValue(String name, double value, int decimals) { - valueResults.add(new ValueResult(name, value, decimals)); - } - - /** - * Prints an HTML table entry onto the stream. - */ - protected void printTableRow(PrintWriter out, String name, String text) { - out.print("" + name + "" + escape(text) + ""); - } - - private String escape(final String text) { - final int maxChars = 40, minChars = 10; - final StringBuilder sb = new StringBuilder(); - boolean first = true; - for (final String word : text.split(" ")) { - if (first) first = false; - else sb.append(" "); - sb.append(chop(word, maxChars, minChars)); - } - return sb.toString(); - } - - /** Split up a monster word into chunks. */ - private String chop(String word, int maxChars, int minChars) { - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < word.length(); i+=maxChars) { - int end = Math.min(i+maxChars, word.length()); - String fragment = word.substring(i,end); - if (i > 0 && fragment.length() > minChars) - sb.append(" "); - sb.append(fragment); - } - return sb.toString(); - } - - /** - * Prints an HTML table entry onto the stream. - */ - protected void printTableRow(PrintWriter out, String name, double number, int decimalPlaces) { - String stringNum = IJ.d2s(number, decimalPlaces); - printTableRow(out, name, stringNum); - } - - /** - * This method creates CSS formatted HTML source out of the results stored - * in the member variables and adds some image statistics found in the data - * container. - * - * @return The HTML source to display - */ - protected String makeHtmlText() { - - StringWriter sout = new StringWriter(); - PrintWriter out = new PrintWriter(sout); - - out.print(""); - // add some style information - out.print(""); - out.print(""); - - // print out warnings, if any - if (warnings.size() > 0) { - out.print("

Warnings

"); - // Print out the table - out.print(""); - out.print(""); - for (Warning w : warnings) { - printTableRow(out, w.getShortMessage(), w.getLongMessage()); - } - out.println("
TypeMessage
"); - } else { - out.print("

No warnings occurred.

"); - } - - // Spit warnings to the IJ log - IJ.log("!!! WARNINGS !!!"); - for (Warning war : warnings) { - IJ.log("Warning! " + war.getShortMessage() + " - " + war.getLongMessage()); - } - // print out simple value results - out.print("

Results

"); - // Print out the table - // out.print(""); - out.print("
"); - out.print(""); - - // Print table rows and spit results to the IJ log. - IJ.log("RESULTS:"); - for (ValueResult vr : valueResults) { - if (vr.isNumber) { - printTableRow(out, vr.name, vr.number, vr.decimals); - IJ.log(vr.name + ", " + IJ.d2s(vr.number, vr.decimals)); - } else { - printTableRow(out, vr.name, vr.value); - IJ.log(vr.name + ", " + vr.value); - } - } - - out.println("
NameResult
"); - out.print(""); - out.close(); - - // Get the string of HTML from the StringWriter and return it. - return sout.toString(); - } - - /** - * If the currently selected ImageResult is an HistrogramResult, a table of - * x-values, y-values and the counts. - */ - protected void showList() { - /* - * check if we are dealing with an histogram result or a generic image - * result - */ - if (isHistogram(currentlyDisplayedImageResult)) { - Histogram2D hr = mapOf2DHistograms.get(currentlyDisplayedImageResult); - double xBinWidth = 1.0 / hr.getXBinWidth(); - double yBinWidth = 1.0 / hr.getYBinWidth(); - // check if we have bins of size one or other ones - boolean xBinWidthIsOne = Math.abs(xBinWidth - 1.0) < 0.00001; - boolean yBinWidthIsOne = Math.abs(yBinWidth - 1.0) < 0.00001; - // configure table headings accordingly - String vHeadingX = xBinWidthIsOne ? "X value" : "X bin start"; - String vHeadingY = yBinWidthIsOne ? "Y value" : "Y bin start"; - // get the actual histogram data - String histogramData = hr.getData(); - - TextWindow tw = new TextWindow(getTitle(), vHeadingX + "\t" + vHeadingY + "\tcount", histogramData, 250, - 400); - tw.setVisible(true); - } - } - - /** - * If the currently selected ImageResult is an HistogramRestult, this method - * copies its data into to the clipboard. - */ - protected void copyToClipboard() { - /* - * check if we are dealing with an histogram result or a generic image - * result - */ - if (isHistogram(currentlyDisplayedImageResult)) { - /* - * try to get the system clipboard and return if we can't get it - */ - Clipboard systemClipboard = null; - try { - systemClipboard = getToolkit().getSystemClipboard(); - } catch (Exception e) { - systemClipboard = null; - } - - if (systemClipboard == null) { - IJ.error("Unable to copy to Clipboard."); - return; - } - // copy histogram values - IJ.showStatus("Copying histogram values..."); - - String text = mapOf2DHistograms.get(currentlyDisplayedImageResult).getData(); - StringSelection contents = new StringSelection(text); - systemClipboard.setContents(contents, this); - - IJ.showStatus(text.length() + " characters copied to Clipboard"); - } - } - - @Override - public void mouseDragged(MouseEvent e) { - // nothing to do here - } - - @Override - public void mouseMoved(MouseEvent e) { - if (e.getSource().equals(imagePanel)) { - /* - * calculate the mouse position relative to the upper left corner of - * the displayed image. - */ - final int imgWidth = imagePanel.getSrcRect().width; - final int imgHeight = imagePanel.getSrcRect().height; - int displayWidth = (int) (imgWidth * imagePanel.getMagnification()); - int displayHeight = (int) (imgHeight * imagePanel.getMagnification()); - int offsetX = (imagePanel.getWidth() - displayWidth) / 2; - int offsetY = (imagePanel.getHeight() - displayHeight) / 2; - int onImageX = imagePanel.screenX(e.getX() - offsetX); - int onImageY = imagePanel.screenY(e.getY() - offsetY); - - // make sure we stay within the image boundaries - if (onImageX >= 0 && onImageX < imgWidth && onImageY >= 0 && onImageY < imgHeight) { - mouseMoved(onImageX, onImageY); - } else { - IJ.showStatus(""); - } - } - } - - /** - * Displays information about the pixel below the mouse cursor of the - * currently displayed image result. The coordinates passed are expected to - * be within the image boundaries. - * - * @param x - * @param y - */ - public void mouseMoved(int x, int y) { - final ImageJ ij = IJ.getInstance(); - if (ij != null && currentlyDisplayedImageResult != null) { - /* - * If Alt key is not pressed, display the calibrated data. If not, - * display image positions and data. Non log image intensity from - * original image or 2D histogram result is always shown in status - * bar, not the log intensity that might actually be displayed in - * the image. - */ - if (!IJ.altKeyDown()) { - - // the alt key is not pressed use x and y values that are bin - // widths or calibrated intensities not the x y image - // coordinates. - if (isHistogram(currentlyDisplayedImageResult)) { - Histogram2D histogram = mapOf2DHistograms.get(currentlyDisplayedImageResult); - - synchronized (pixelAccessCursor) { - // set position of output cursor - pixelAccessCursor.setPosition(x, 0); - pixelAccessCursor.setPosition(y, 1); - - // for a histogram coordinate display we need to invert - // the Y axis - y = (int) currentlyDisplayedImageResult.dimension(1) - 1 - y; - - // get current value at position - RandomAccess cursor = (RandomAccess) pixelAccessCursor; - long val = cursor.get().getIntegerLong(); - - double calibratedXBinBottom = histogram.getXMin() + x / histogram.getXBinWidth(); - double calibratedXBinTop = histogram.getXMin() + (x + 1) / histogram.getXBinWidth(); - - double calibratedYBinBottom = histogram.getYMin() + y / histogram.getYBinWidth(); - double calibratedYBinTop = histogram.getYMin() + (y + 1) / histogram.getYBinWidth(); - - IJ.showStatus("x = " + IJ.d2s(calibratedXBinBottom) + " to " + IJ.d2s(calibratedXBinTop) - + ", y = " + IJ.d2s(calibratedYBinBottom) + " to " + IJ.d2s(calibratedYBinTop) - + ", value = " + val); - } - } else { - RandomAccessibleInterval img = (RandomAccessibleInterval) currentlyDisplayedImageResult; - ImagePlus imp = ImageJFunctions.wrapFloat(img, "TODO"); - imp.mouseMoved(x, y); - } - } else { - // alt key is down, so show the image coordinates for x y in - // status bar. - RandomAccessibleInterval img = (RandomAccessibleInterval) currentlyDisplayedImageResult; - ImagePlus imp = ImageJFunctions.wrapFloat(img, "TODO"); - imp.mouseMoved(x, y); - } - } - } - - /** - * Draws the passed ImageResult on the ImagePlus of this class. If the image - * is part of a CompositeImageResult then contained lines will also be drawn - */ - protected void drawImage(RandomAccessibleInterval> img) { - // get ImgLib image as ImageJ image - imp = ImageJFunctions.wrapFloat((RandomAccessibleInterval) img, "TODO"); - imagePanel.updateImage(imp); - // set the display range - - // check if a LUT should be applied - if (listOfLUTs.containsKey(img)) { - // select linked look up table - IJ.run(imp, listOfLUTs.get(img), null); - } - imp.getProcessor().resetMinAndMax(); - - boolean overlayModified = false; - Overlay overlay = new Overlay(); - - // if it is the 2d histogram, we want to show the regression line - if (isHistogram(img)) { - Histogram2D histogram = mapOf2DHistograms.get(img); - /* - * check if we should draw a regression line for the current - * histogram. - */ - if (histogram.getDrawingSettings().contains(Histogram2D.DrawingFlags.RegressionLine)) { - AutoThresholdRegression autoThreshold = dataContainer.getAutoThreshold(); - if (histogram != null && autoThreshold != null) { - if (img == histogram.getPlotImage()) { - drawLine(overlay, img, autoThreshold.getAutoThresholdSlope(), - autoThreshold.getAutoThresholdIntercept()); - overlayModified = true; - } - } - } - } - - if (overlayModified) { - overlay.setStrokeColor(java.awt.Color.WHITE); - imp.setOverlay(overlay); - } - - imagePanel.repaint(); - } - - /** - * Tests whether the given image is a histogram or not. - * - * @param img - * The image to test - * @return true if histogram, false otherwise - */ - protected boolean isHistogram(RandomAccessibleInterval> img) { - return mapOf2DHistograms.containsKey(img); - } - - /** - * Draws the line on the overlay. - */ - protected void drawLine(Overlay overlay, RandomAccessibleInterval> img, double slope, - double intercept) { - double startX, startY, endX, endY; - long imgWidth = img.dimension(0); - long imgHeight = img.dimension(1); - /* - * since we want to draw the line over the whole image we can directly - * use screen coordinates for x values. - */ - startX = 0.0; - endX = imgWidth; - - // check if we can get some exta information for drawing - if (isHistogram(img)) { - Histogram2D histogram = mapOf2DHistograms.get(img); - // get calibrated start y coordinates - double calibratedStartY = slope * histogram.getXMin() + intercept; - double calibratedEndY = slope * histogram.getXMax() + intercept; - // convert calibrated coordinates to screen coordinates - startY = calibratedStartY * histogram.getYBinWidth(); - endY = calibratedEndY * histogram.getYBinWidth(); - } else { - startY = slope * startX + intercept; - endY = slope * endX + intercept; - } - - /* - * since the screen origin is in the top left of the image, we need to - * x-mirror our line - */ - startY = (imgHeight - 1) - startY; - endY = (imgHeight - 1) - endY; - // create the line ROI and add it to the overlay - Line lineROI = new Line(startX, startY, endX, endY); - /* - * Set drawing width of line to one, in case it has been changed - * globally. - */ - lineROI.setStrokeWidth(1.0f); - overlay.add(lineROI); - } - - protected void adjustDisplayedImage(RandomAccessibleInterval> img) { - /* - * when changing the result image to display need to set the image we - * were looking at back to not log scale, so we don't log it twice if - * its reselected. - */ - if (log.isSelected()) - toggleLogarithmic(false); - - currentlyDisplayedImageResult = img; - pixelAccessCursor = img.randomAccess(); - - // Currently disabled, due to lag of non-histograms :-) - // disable list and copy button if it is no histogram result - listButton.setEnabled(isHistogram(img)); - copyButton.setEnabled(isHistogram(img)); - - drawImage(img); - toggleLogarithmic(log.isSelected()); - - // ensure a valid layout, we changed the image - getContentPane().validate(); - getContentPane().repaint(); - } - - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - RandomAccessibleInterval> img = ((NamedContainer>>) (e - .getItem())).getObject(); - adjustDisplayedImage(img); - } - } - - protected void toggleLogarithmic(boolean enabled) { - if (imp == null) - return; - ImageProcessor ip = imp.getProcessor(); - if (enabled) { - ip.snapshot(); - ip.log(); - ip.resetMinAndMax(); - } else - ip.reset(); - imagePanel.repaint(); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == log) { - toggleLogarithmic(log.isSelected()); - } - } - - @Override - public void lostOwnership(Clipboard clipboard, Transferable contents) { - // nothing to do here - } -} diff --git a/src/main/java/sc/fiji/coloc/results/ValueResult.java b/src/main/java/sc/fiji/coloc/results/ValueResult.java deleted file mode 100644 index f021da4..0000000 --- a/src/main/java/sc/fiji/coloc/results/ValueResult.java +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -/** - * A small structure to keep decimal places information - * with numbers along with a name or a simple named text. - */ -public class ValueResult { - public String name; - public double number; - public int decimals; - public String value; - public boolean isNumber; - - public ValueResult( String name, double number, int decimals ) { - this.name = name; - this.number = number; - this.decimals = decimals; - this.isNumber = true; - } - - public ValueResult( String name, String value) { - this.name = name; - this.value = value; - this.isNumber = false; - } -} diff --git a/src/main/java/sc/fiji/coloc/results/Warning.java b/src/main/java/sc/fiji/coloc/results/Warning.java deleted file mode 100644 index 7f76ef2..0000000 --- a/src/main/java/sc/fiji/coloc/results/Warning.java +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.results; - -/** - * A class representing a warning, combining a short and - * a long message. Typically Algorithms can produce such - * warnings if they find problems with the input data. - */ -public class Warning -{ - private String shortMessage; - private String longMessage; - - public Warning(String shortMessage, String longMessage) - { - this.shortMessage = shortMessage; - this.longMessage = longMessage; - } - - public String getShortMessage() { - return shortMessage; - } - - public String getLongMessage() { - return longMessage; - } - -} diff --git a/src/main/resources/plugins.config b/src/main/resources/plugins.config index c61b370..95aef71 100644 --- a/src/main/resources/plugins.config +++ b/src/main/resources/plugins.config @@ -1,24 +1,22 @@ -### -# #%L -# Fiji's plugin for colocalization analysis. -# %% -# Copyright (C) 2009 - 2017 Fiji 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 3 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% -### -Analyze>Colocalization, "Colocalization Threshold", sc.fiji.coloc.Colocalisation_Threshold -Analyze>Colocalization, "Colocalization Test", sc.fiji.coloc.Colocalisation_Test -Analyze>Colocalization, "Coloc 2", sc.fiji.coloc.Coloc_2 +### +# #%L +# Running a Macro from a Macro, bypassing the old builtin way, to support script parameters. +# %% +# Copyright (C) 2017 Olivier Burri +# %% +# 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 3 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% +### +Plugins>BIOP>Macro, "BIOP Run Macro...", ch.epfl.biop.macrorunner.B_Run_Macro diff --git a/src/main/resources/script_templates/Examples/Colocalisation.groovy b/src/main/resources/script_templates/Examples/Colocalisation.groovy deleted file mode 100644 index 530339c..0000000 --- a/src/main/resources/script_templates/Examples/Colocalisation.groovy +++ /dev/null @@ -1,61 +0,0 @@ -// @ImagePlus imp1 -// @ImagePlus imp2 - -// Colocalisation.groovy -// -// This script demonstrates programmatic usage of Fiji's Coloc 2 plugin, -// including how to extract quantitative measurements after execution. - -import sc.fiji.coloc.Coloc_2 -coloc2 = new Coloc_2() - -indexMask = 0 -indexRegr = 0 -autoSavePdf = false -displayImages = false -displayShuffledCostes = false -useLiCh1 = true -useLiCh2 = true -useLiICQ = true -useSpearmanRank = true -useManders = true -useKendallTau = true -useScatterplot = true -useCostes = true -psf = 3 -nrCostesRandomisations = 10 - -coloc2.initializeSettings( - imp1, - imp2, - indexMask, - indexRegr, - autoSavePdf, - displayImages, - displayShuffledCostes, - useLiCh1, - useLiCh2, - useLiICQ, - useSpearmanRank, - useManders, - useKendallTau, - useScatterplot, - useCostes, - psf, - nrCostesRandomisations) - -img1 = coloc2.img1 -img2 = coloc2.img2 -box = coloc2.masks[0].roi -mask = coloc2.masks[0].mask - -// NB: Passing a different bounding box and/or mask here -// may work, but is (as of this writing) UNTESTED. -results = coloc2.colocalise(img1, img2, box, mask, null) -for (v in results.values()) { - println(v.name + " = " + (v.isNumber ? v.number : v.value)) -} -println("I also have histograms:") -for (h in results.histograms()) { - println("\t" + h) -} diff --git a/src/test/java/sc/fiji/coloc/Main.java b/src/test/java/sc/fiji/coloc/Main.java deleted file mode 100644 index 1389672..0000000 --- a/src/test/java/sc/fiji/coloc/Main.java +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc; - -import ij.IJ; -import ij.ImageJ; -import ij.ImagePlus; -import ij.plugin.ChannelSplitter; - -/** - * Test class for Coloc 2 functionality. - * - * @author Ellen T Arena - */ -public class Main { - - - /** - * Main method for debugging. - * - * For debugging, it is convenient to have a method that starts ImageJ, loads an - * image and calls the plugin, e.g. after setting breakpoints. - * - * @param args unused - */ - public static void main(String[] args) { - // start ImageJ - new ImageJ(); - - // open the FluorescentCells sample (to test single slice images) - ImagePlus fluorCellImage = IJ.openImage("http://imagej.net/images/FluorescentCells.zip"); - ImagePlus[] fluorCellchannels = ChannelSplitter.split(fluorCellImage); - fluorCellchannels[0].show(); - fluorCellchannels[1].show(); - // run the plugin, Coloc 2 - IJ.runPlugIn(Coloc_2.class.getName(),"channel_1=C1-FluorescentCells.tif channel_2=C2-FluorescentCells.tif roi_or_mask= threshold_regression=Costes display_images_in_result li_histogram_channel_1 li_histogram_channel_2 li_icq spearman's_rank_correlation manders'_correlation kendall's_tau_rank_correlation 2d_instensity_histogram costes'_significance_test psf=3 costes_randomisations=10"); - -// // open the Confocal Series sample (to test z-stacks) -// ImagePlus confocalImage = IJ.openImage("http://imagej.net/images/confocal-series.zip"); -// ImagePlus[] confocalchannels = ChannelSplitter.split(confocalImage); -// confocalchannels[0].show(); -// confocalchannels[1].show(); -// // run the plugin, Coloc 2 -// IJ.runPlugIn(Coloc_2.class.getName(), "channel_1=C1-confocal-series.tif channel_2=C2-confocal-series.tif roi_or_mask= threshold_regression=Costes display_images_in_result li_histogram_channel_1 li_histogram_channel_2 li_icq spearman's_rank_correlation manders'_correlation kendall's_tau_rank_correlation 2d_instensity_histogram costes'_significance_test psf=3 costes_randomisations=10"); - -// // testing RGB image samples... -// ImagePlus fluorCellImage = IJ.openImage("http://imagej.net/images/hela-cells.zip"); -// ImagePlus[] fluorCellchannels = ChannelSplitter.split(fluorCellImage); -// fluorCellchannels[0].show(); -// fluorCellchannels[1].show(); -// IJ.run("RGB Color"); -// // run the plugin, Coloc 2 -// IJ.runPlugIn(Coloc_2.class.getName(),"channel_1=C1-hela-cells.tif channel_2=C2-hela-cells.tif roi_or_mask= threshold_regression=Costes display_images_in_result li_histogram_channel_1 li_histogram_channel_2 li_icq spearman's_rank_correlation manders'_correlation kendall's_tau_rank_correlation 2d_instensity_histogram costes'_significance_test psf=3 costes_randomisations=10"); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/AutoThresholdRegressionTest.java b/src/test/java/sc/fiji/coloc/tests/AutoThresholdRegressionTest.java deleted file mode 100644 index 157e4c8..0000000 --- a/src/test/java/sc/fiji/coloc/tests/AutoThresholdRegressionTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.type.numeric.integer.UnsignedByteType; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.AutoThresholdRegression; -import sc.fiji.coloc.algorithms.AutoThresholdRegression.Implementation; -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.PearsonsCorrelation; -import sc.fiji.coloc.gadgets.DataContainer; - - -public class AutoThresholdRegressionTest extends ColocalisationTest { - - @Test - public void clampHelperTest() throws MissingPreconditionException { - assertEquals(4, AutoThresholdRegression.clamp(5, 1, 4), 0.00001); - assertEquals(1, AutoThresholdRegression.clamp(-2, 1, 4), 0.00001); - assertEquals(1, AutoThresholdRegression.clamp(5, 1, 1), 0.00001); - assertEquals(2, AutoThresholdRegression.clamp(2, -1, 3), 0.00001); - } - - /** - * This test makes sure the test images A and B lead to the same thresholds, - * regardless whether they are added in the order A, B or B, A to the data - * container. - * - * @throws MissingPreconditionException - */ - @Test - public void cummutativityTest() throws MissingPreconditionException { - _cummutativityTest(Implementation.Costes); - _cummutativityTest(Implementation.Bisection); - } - - protected void _cummutativityTest(Implementation atrImplementation) - throws MissingPreconditionException { - PearsonsCorrelation pc1 = - new PearsonsCorrelation( - PearsonsCorrelation.Implementation.Fast); - PearsonsCorrelation pc2 = - new PearsonsCorrelation( - PearsonsCorrelation.Implementation.Fast); - - AutoThresholdRegression atr1 = - new AutoThresholdRegression(pc1, atrImplementation); - AutoThresholdRegression atr2 = - new AutoThresholdRegression(pc2, atrImplementation); - - RandomAccessibleInterval img1 = syntheticNegativeCorrelationImageCh1; - RandomAccessibleInterval img2 = syntheticNegativeCorrelationImageCh2; - - DataContainer container1 = - new DataContainer(img1, img2, 1, 1, - "Channel 1", "Channel 2"); - - DataContainer container2 = - new DataContainer(img2, img1, 1, 1, - "Channel 2", "Channel 1"); - - atr1.execute(container1); - atr2.execute(container2); - - assertEquals(atr1.getCh1MinThreshold(), atr2.getCh2MinThreshold()); - assertEquals(atr1.getCh1MaxThreshold(), atr2.getCh2MaxThreshold()); - assertEquals(atr1.getCh2MinThreshold(), atr2.getCh1MinThreshold()); - assertEquals(atr1.getCh2MaxThreshold(), atr2.getCh1MaxThreshold()); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/ColocalisationTest.java b/src/test/java/sc/fiji/coloc/tests/ColocalisationTest.java deleted file mode 100644 index 56861f2..0000000 --- a/src/test/java/sc/fiji/coloc/tests/ColocalisationTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.Img; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.integer.UnsignedByteType; - -import org.junit.After; -import org.junit.Before; - -import sc.fiji.coloc.gadgets.MaskFactory; - - -public abstract class ColocalisationTest { - - // images and meta data for zero correlation - RandomAccessibleInterval zeroCorrelationImageCh1; - RandomAccessibleInterval zeroCorrelationImageCh2; - RandomAccessibleInterval zeroCorrelationAlwaysTrueMask; - double zeroCorrelationImageCh1Mean; - double zeroCorrelationImageCh2Mean; - - // images and meta data for positive correlation test - // and real noisy image Manders' coeff with mask test - RandomAccessibleInterval positiveCorrelationImageCh1; - RandomAccessibleInterval positiveCorrelationImageCh2; - // open mask image as a bit type cursor - Img positiveCorrelationMaskImage; - RandomAccessibleInterval positiveCorrelationAlwaysTrueMask; - double positiveCorrelationImageCh1Mean; - double positiveCorrelationImageCh2Mean; - - // images and meta data for a synthetic negative correlation dataset - RandomAccessibleInterval syntheticNegativeCorrelationImageCh1; - RandomAccessibleInterval syntheticNegativeCorrelationImageCh2; - RandomAccessibleInterval syntheticNegativeCorrelationAlwaysTrueMask; - double syntheticNegativeCorrelationImageCh1Mean; - double syntheticNegativeCorrelationImageCh2Mean; - - // images like in the Manders paper - RandomAccessibleInterval mandersA, mandersB, mandersC, mandersD, - mandersE, mandersF, mandersG, mandersH, mandersI; - RandomAccessibleInterval mandersAlwaysTrueMask; - - /** - * This method is run before every single test is run and is meant to set up - * the images and meta data needed for testing image colocalisation. - */ - @Before - public void setup() { - zeroCorrelationImageCh1 = TestImageAccessor.loadTiffFromJar("/greenZstack.tif"); - zeroCorrelationImageCh1Mean = ImageStatistics.getImageMean(zeroCorrelationImageCh1); - - zeroCorrelationImageCh2 = TestImageAccessor.loadTiffFromJar("/redZstack.tif"); - zeroCorrelationImageCh2Mean = ImageStatistics.getImageMean(zeroCorrelationImageCh2); - - final long[] dimZeroCorrCh1 = new long[ zeroCorrelationImageCh1.numDimensions() ]; - zeroCorrelationImageCh1.dimensions(dimZeroCorrCh1); - zeroCorrelationAlwaysTrueMask = MaskFactory.createMask(dimZeroCorrCh1, true); - - positiveCorrelationImageCh1 = TestImageAccessor.loadTiffFromJar("/colocsample1b-green.tif"); - positiveCorrelationImageCh1Mean = ImageStatistics.getImageMean(positiveCorrelationImageCh1); - - positiveCorrelationImageCh2 = TestImageAccessor.loadTiffFromJar("/colocsample1b-red.tif"); - positiveCorrelationImageCh2Mean = ImageStatistics.getImageMean(positiveCorrelationImageCh2); - - positiveCorrelationMaskImage = TestImageAccessor.loadTiffFromJarAsImg("/colocsample1b-mask.tif"); - - final long[] dimPosCorrCh1 = new long[ positiveCorrelationImageCh1.numDimensions() ]; - positiveCorrelationImageCh1.dimensions(dimPosCorrCh1); - positiveCorrelationAlwaysTrueMask = MaskFactory.createMask(dimPosCorrCh1, true); - - syntheticNegativeCorrelationImageCh1 = TestImageAccessor.loadTiffFromJar("/syntheticNegCh1.tif"); - syntheticNegativeCorrelationImageCh1Mean = ImageStatistics.getImageMean(syntheticNegativeCorrelationImageCh1); - - syntheticNegativeCorrelationImageCh2 = TestImageAccessor.loadTiffFromJar("/syntheticNegCh2.tif"); - syntheticNegativeCorrelationImageCh2Mean = ImageStatistics.getImageMean(syntheticNegativeCorrelationImageCh2); - - final long[] dimSynthNegCorrCh1 = new long[ syntheticNegativeCorrelationImageCh1.numDimensions() ]; - syntheticNegativeCorrelationImageCh1.dimensions(dimSynthNegCorrCh1); - syntheticNegativeCorrelationAlwaysTrueMask = MaskFactory.createMask(dimSynthNegCorrCh1, true); - - mandersA = TestImageAccessor.loadTiffFromJar("/mandersA.tiff"); - mandersB = TestImageAccessor.loadTiffFromJar("/mandersB.tiff"); - mandersC = TestImageAccessor.loadTiffFromJar("/mandersC.tiff"); - mandersD = TestImageAccessor.loadTiffFromJar("/mandersD.tiff"); - mandersE = TestImageAccessor.loadTiffFromJar("/mandersE.tiff"); - mandersF = TestImageAccessor.loadTiffFromJar("/mandersF.tiff"); - mandersG = TestImageAccessor.loadTiffFromJar("/mandersG.tiff"); - mandersH = TestImageAccessor.loadTiffFromJar("/mandersH.tiff"); - mandersI = TestImageAccessor.loadTiffFromJar("/mandersI.tiff"); - - final long[] dimMandersA = new long[ mandersA.numDimensions() ]; - mandersA.dimensions(dimMandersA); - mandersAlwaysTrueMask = MaskFactory.createMask(dimMandersA, true); - } - - /** - * This method is run after every single test and is meant to clean up. - */ - @After - public void cleanup() { - // nothing to do - } - - /** - * Creates a ROI offset array with a distance of 1/4 to the origin - * in each dimension. - */ - protected > long[] createRoiOffset(RandomAccessibleInterval img) { - final long[] offset = new long[ img.numDimensions() ]; - img.dimensions(offset); - for (int i=0; i> long[] createRoiSize(RandomAccessibleInterval img) { - final long[] size = new long[ img.numDimensions() ]; - img.dimensions(size); - for (int i=0; i. - * #L% - */ -package sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.LiICQ; -import sc.fiji.coloc.algorithms.MandersColocalization; -import sc.fiji.coloc.algorithms.MandersColocalization.MandersResults; -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.PearsonsCorrelation; -import sc.fiji.coloc.algorithms.SpearmanRankCorrelation; - -public class CommutativityTest extends ColocalisationTest { - - /** - * This test makes sure the test images A and B lead to the same results, - * regardless whether they are added in the order A, B or B, A to the data - * container. - * - * @throws MissingPreconditionException - */ - @Test - public void cummutativityTest() throws MissingPreconditionException { - assertCommutativity(zeroCorrelationImageCh1, zeroCorrelationImageCh2, - zeroCorrelationAlwaysTrueMask, zeroCorrelationImageCh1Mean, - zeroCorrelationImageCh2Mean); - assertCommutativity(positiveCorrelationImageCh1, positiveCorrelationImageCh1, - positiveCorrelationAlwaysTrueMask, positiveCorrelationImageCh1Mean, - positiveCorrelationImageCh2Mean); - assertCommutativity(syntheticNegativeCorrelationImageCh1, - syntheticNegativeCorrelationImageCh2, - syntheticNegativeCorrelationAlwaysTrueMask, - syntheticNegativeCorrelationImageCh1Mean, - syntheticNegativeCorrelationImageCh2Mean); - } - - protected static > void assertCommutativity( - RandomAccessibleInterval ch1, RandomAccessibleInterval ch2, - RandomAccessibleInterval mask, double mean1, double mean2) - throws MissingPreconditionException - { - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor1 = new TwinCursor(ch1.randomAccess(), - ch2.randomAccess(), Views.iterable(mask).localizingCursor()); - TwinCursor cursor2 = new TwinCursor(ch1.randomAccess(), - ch2.randomAccess(), Views.iterable(mask).localizingCursor()); - - // get the Pearson's values - double pearsonsR1 = PearsonsCorrelation.fastPearsons(cursor1); - double pearsonsR2 = PearsonsCorrelation.fastPearsons(cursor2); - // check Pearsons R is the same - assertEquals(pearsonsR1, pearsonsR2, 0.0001); - - // get Li's ICQ values - double icq1 = LiICQ.calculateLisICQ(cursor1, mean1, mean2); - double icq2 = LiICQ.calculateLisICQ(cursor2, mean2, mean1); - // check Li's ICQ is the same - assertEquals(icq1, icq2, 0.0001); - - // get Manders values - MandersColocalization mc = new MandersColocalization(); - MandersResults manders1 = mc.calculateMandersCorrelation(cursor1, - ch1.randomAccess().get().createVariable()); - MandersResults manders2 = mc.calculateMandersCorrelation(cursor2, - ch2.randomAccess().get().createVariable()); - // check Manders m1 and m2 values are the same - assertEquals(manders1.m1, manders2.m2, 0.0001); - assertEquals(manders1.m2, manders2.m1, 0.0001); - - // calculate Spearman's Rank rho values - SpearmanRankCorrelation src = new SpearmanRankCorrelation(); - double rho1 = src.calculateSpearmanRank(cursor1); - double rho2 = src.calculateSpearmanRank(cursor2); - // make sure both ranks are the same - assertEquals(rho1, rho2, 0.0001); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/CostesSignificanceTest.java b/src/test/java/sc/fiji/coloc/tests/CostesSignificanceTest.java deleted file mode 100644 index c583bdb..0000000 --- a/src/test/java/sc/fiji/coloc/tests/CostesSignificanceTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertTrue; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.type.numeric.real.FloatType; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.AutoThresholdRegression; -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.PearsonsCorrelation; -import sc.fiji.coloc.gadgets.DataContainer; - -/** - * This class contains JUnit 4 test cases for the Costes - * statistical significance test. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class CostesSignificanceTest extends ColocalisationTest { - - /** - * This test checks the Costes statistical significance test implementation - * by artificially disturbing known colocalisation. It simulates what Costes - * describes in figure 3 of section "Simulated data". An image representing - * colocalised data is generated. This is put onto two random Perlin noise - * images. A smoothing step is applied after the combination. With the two - * resulting images the Costes calculation and shuffling is done. These steps - * are done multiple times, every time with an increasing percentage of - * colocalised data in the images. As stated by Costes, colocalisation data - * percentages above three percent should be detected (P value > 0.95. This - * is the assertion of this test and checked with every iteration. Percentages - * to test are calculated as percentage = 10^x. Five iterations are done, - * increasing "x" in steps of 0.5, starting at 0. The test uses circles with - * a diameter of 7 as objects (similar to Costes' paper, he uses 7x7 squares). - */ - @Test - public void backgroundNoiseTest() throws MissingPreconditionException { - final int width = 512; - final int height = 512; - final double z = 2.178; - final double scale = 0.1; - final int psf = 3; - final int objectSize = 7; - final double[] sigma = new double[] {3.0,3.0}; - - for (double exp=0; exp < 2.5; exp=exp+0.5) { - double colocPercentage = Math.pow(10, exp); - RandomAccessibleInterval ch1 = TestImageAccessor.producePerlinNoiseImage( - new FloatType(), width, height, z, scale); - RandomAccessibleInterval ch2 = TestImageAccessor.producePerlinNoiseImage( - new FloatType(), width, height, z, scale); - /* calculate the number of colocalised pixels, based on the percentage and the - * space one noise point will take (here 9, because we use 3x3 dots) - */ - int nrColocPixels = (int) ( ( (width * height / 100.0) * colocPercentage ) / (objectSize * objectSize) ); - // create non-smoothed coloc image. add it to the noise images and smooth them - RandomAccessibleInterval colocImg = TestImageAccessor.produceNoiseImage( - width, height, objectSize, nrColocPixels); - TestImageAccessor.combineImages(ch1, colocImg); - ch1 = TestImageAccessor.gaussianSmooth(ch1, sigma); - TestImageAccessor.combineImages(ch2, colocImg); - ch2 = TestImageAccessor.gaussianSmooth(ch2, sigma); - - DataContainer container - = new DataContainer(ch1, ch2, 1, 1, "Channel 1", "Channel 2"); - - PearsonsCorrelation pc - = new PearsonsCorrelation(PearsonsCorrelation.Implementation.Fast); - AutoThresholdRegression atr - = new AutoThresholdRegression(pc); - container.setAutoThreshold(atr); - atr.execute(container); - try { - pc.execute(container); - } - catch (MissingPreconditionException e) { - /* this can happen for random noise data in seldom cases, - * but we are not after this here. The cases that are - * important for Costes work well, but are again sanity - * checked here. - */ - if (pc.getPearsonsCorrelationValue() == Double.NaN) - throw e; - } - - sc.fiji.coloc.algorithms.CostesSignificanceTest costes - = new sc.fiji.coloc.algorithms.CostesSignificanceTest(pc, psf, 10, false); - costes.execute(container); - - // check if we can expect a high P - if (colocPercentage > 3.0) { - double pVal = costes.getCostesPValue(); - assertTrue("Costes P value was " + pVal, pVal > 0.95); - } - } - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/ImprovedNoise.java b/src/test/java/sc/fiji/coloc/tests/ImprovedNoise.java deleted file mode 100644 index cbd9ac9..0000000 --- a/src/test/java/sc/fiji/coloc/tests/ImprovedNoise.java +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -/** - * JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. - * From: http://mrl.nyu.edu/~perlin/noise/ - */ -public final class ImprovedNoise { - static public double noise(double x, double y, double z) { - int X = (int)Math.floor(x) & 255, // FIND UNIT CUBE THAT - Y = (int)Math.floor(y) & 255, // CONTAINS POINT. - Z = (int)Math.floor(z) & 255; - x -= Math.floor(x); // FIND RELATIVE X,Y,Z - y -= Math.floor(y); // OF POINT IN CUBE. - z -= Math.floor(z); - double u = fade(x), // COMPUTE FADE CURVES - v = fade(y), // FOR EACH OF X,Y,Z. - w = fade(z); - int A = p[X ]+Y, AA = p[A]+Z, AB = p[A+1]+Z, // HASH COORDINATES OF - B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; // THE 8 CUBE CORNERS, - - return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ), // AND ADD - grad(p[BA ], x-1, y , z )), // BLENDED - lerp(u, grad(p[AB ], x , y-1, z ), // RESULTS - grad(p[BB ], x-1, y-1, z ))),// FROM 8 - lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ), // CORNERS - grad(p[BA+1], x-1, y , z-1 )), // OF CUBE - lerp(u, grad(p[AB+1], x , y-1, z-1 ), - grad(p[BB+1], x-1, y-1, z-1 )))); - } - static double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); } - static double lerp(double t, double a, double b) { return a + t * (b - a); } - static double grad(int hash, double x, double y, double z) { - int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE - double u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. - v = h<4 ? y : h==12||h==14 ? x : z; - return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); - } - static final int p[] = new int[512], permutation[] = { 151,160,137,91,90,15, - 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, - 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, - 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, - 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, - 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, - 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, - 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, - 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, - 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, - 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, - 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 - }; - static { for (int i=0; i < 256 ; i++) p[256+i] = p[i] = permutation[i]; } -} diff --git a/src/test/java/sc/fiji/coloc/tests/KendallTauTest.java b/src/test/java/sc/fiji/coloc/tests/KendallTauTest.java deleted file mode 100644 index f53a83b..0000000 --- a/src/test/java/sc/fiji/coloc/tests/KendallTauTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -import net.imglib2.PairIterator; -import net.imglib2.type.numeric.real.DoubleType; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.KendallTauRankCorrelation; -import sc.fiji.coloc.algorithms.MissingPreconditionException; - -/** - * Tests the Kendall Tau implementation. - */ -public class KendallTauTest { - - private boolean exhaustive = false; - - @Test - public void testSimple() throws MissingPreconditionException { - assumeTrue(!exhaustive); - // From Armitage P, Berry G. Statistical Methods in Medical Research (3rd edition). Blackwell 1994, p. 466. - assertTau(23.0 / 45.0, new int[] { 4, 10, 3, 1, 9, 2, 6, 7, 8, 5 }, new int[] { 5, 8, 6, 2, 10, 3, 9, 4, 7, 1 }); - } - - @Test - public void testPathological() throws MissingPreconditionException { - assumeTrue(!exhaustive); - assertTau(Double.NaN, new int[] { 1, 1, 1, 1 }, new int[] { 2, 2, 2, 2 }); - } - - @Test - public void testSomeDuplicates() throws MissingPreconditionException { - assumeTrue(!exhaustive); - // for pairs (1, 3), (1, 2), (2, 1), (3, 1), - // n = 4, - // n0 = n * (n - 1) / 2 = 4 * 3 / 2 = 6 - // n1 = 1 + 0 + 0 + 0 = 1 - // n2 = 1 + 0 + 0 + 0 = 1 - // nc = #{ } = 0 - // nd = #{ (1, 3)x(2, 1), (1, 3)x(3, 1), (1, 2)x(2, 1), (1, 2)x(3, 1) } = 4 - // therefore Tau_b = -4 / sqrt(5 * 5) = -0.8 - assertTau(-0.8, new int[] { 1, 1, 2, 3 }, new int[] { 3, 2, 1, 1 }); - } - - private PairIterator pairIterator(final int[] values1, final int[] values2) { - assertEquals(values1.length, values2.length); - return new PairIterator() { - private int i = -1; - private DoubleType ch1 = new DoubleType(); - private DoubleType ch2 = new DoubleType(); - - @Override - public boolean hasNext() { - return i + 1 < values1.length; - } - - @Override - public void reset() { - i = -1; - } - - @Override - public void fwd() { - i++; - } - - @Override - public DoubleType getFirst() { - ch1.set(values1[i]); - return ch1; - } - - @Override - public DoubleType getSecond() { - ch2.set(values2[i]); - return ch2; - } - }; - } - - private void assertTau(final double expected, final int[] values1, final int[] values2) throws MissingPreconditionException { - final PairIterator iter = pairIterator(values1, values2); - assertEquals(expected, KendallTauRankCorrelation.calculateMergeSort(iter), 1e-10); - } - - private int seed; - - private int pseudoRandom() - { - return seed = 3170425 * seed + 132102; - } - - @Test - public void exhaustiveTesting() throws Exception { - assumeTrue(exhaustive); - final int n = 5, m = 10; - final int[] values1 = new int[n], values2 = new int[n]; - for (int i = 0; i < 100; i++) { - for (int j = 0; j < n; j++) { - values1[j] = Math.abs(pseudoRandom()) % m; - values2[j] = Math.abs(pseudoRandom()) % m; - } - final PairIterator iter = pairIterator(values1, values2); - double value1 = KendallTauRankCorrelation.calculateNaive(iter); - iter.reset(); - double value2 = KendallTauRankCorrelation.calculateMergeSort(iter); - if (Double.isNaN(value1)) { - assertTrue("i: " + i + ", value2: " + value2, Double.isInfinite(value2) || Double.isNaN(value2)); - } else { - assertEquals("i: " + i, value1, value2, 1e-10); - } - } - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/LiICQTest.java b/src/test/java/sc/fiji/coloc/tests/LiICQTest.java deleted file mode 100644 index 9a6c5f7..0000000 --- a/src/test/java/sc/fiji/coloc/tests/LiICQTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertTrue; - -import net.imglib2.TwinCursor; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.LiICQ; - -/** - * This class contains JUnit 4 test cases for the calculation of Li's - * ICQ value. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class LiICQTest extends ColocalisationTest { - - /** - * Checks Li's ICQ value for positive correlated images. - */ - @Test - public void liPositiveCorrTest() { - TwinCursor cursor = new TwinCursor( - positiveCorrelationImageCh1.randomAccess(), - positiveCorrelationImageCh2.randomAccess(), - Views.iterable(positiveCorrelationAlwaysTrueMask).localizingCursor()); - // calculate Li's ICQ value - double icq = LiICQ.calculateLisICQ(cursor, positiveCorrelationImageCh1Mean, - positiveCorrelationImageCh2Mean); - assertTrue(icq > 0.34 && icq < 0.35); - } - - /** - * Checks Li's ICQ value for zero correlated images. The ICQ value - * should be about zero. - */ - @Test - public void liZeroCorrTest() { - TwinCursor cursor = new TwinCursor( - zeroCorrelationImageCh1.randomAccess(), - zeroCorrelationImageCh2.randomAccess(), - Views.iterable(zeroCorrelationAlwaysTrueMask).localizingCursor()); - // calculate Li's ICQ value - double icq = LiICQ.calculateLisICQ(cursor, zeroCorrelationImageCh1Mean, - zeroCorrelationImageCh2Mean); - assertTrue(Math.abs(icq) < 0.01); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/MandersColocalizationTest.java b/src/test/java/sc/fiji/coloc/tests/MandersColocalizationTest.java deleted file mode 100644 index ee9238a..0000000 --- a/src/test/java/sc/fiji/coloc/tests/MandersColocalizationTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; - -import net.imglib2.Cursor; -import net.imglib2.TwinCursor; -import net.imglib2.converter.Converter; -import net.imglib2.converter.Converters; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.MandersColocalization; -import sc.fiji.coloc.algorithms.MandersColocalization.MandersResults; -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.gadgets.ThresholdMode; - -/** - * This class contains JUnit 4 test cases for the calculation - * of Manders' split colocalization coefficients - * - * @author Dan White - * @author Tom Kazimiers - */ -public class MandersColocalizationTest extends ColocalisationTest { - - /** - * This method tests artificial test images as detailed in - * the Manders et al. paper, using above zero threshold (none). - * Note: It is not sensitive to choosing the wrong channel to test for - * above threshold, because threshold is same for both channels: above zero, - * and also that the blobs overlap perfectly or not at all. - */ - @Test - public void mandersPaperImagesTest() throws MissingPreconditionException { - MandersColocalization mc = - new MandersColocalization(); - - TwinCursor cursor; - MandersResults r; - // test A-A combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersA.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get().createVariable()); - - assertEquals(1.0d, r.m1, 0.0001); - assertEquals(1.0d, r.m2, 0.0001); - - // test A-B combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersB.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.75d, r.m1, 0.0001); - assertEquals(0.75d, r.m2, 0.0001); - - // test A-C combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersC.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.5d, r.m1, 0.0001); - assertEquals(0.5d, r.m2, 0.0001); - - // test A-D combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersD.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.25d, r.m1, 0.0001); - assertEquals(0.25d, r.m2, 0.0001); - - // test A-E combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersE.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.0d, r.m1, 0.0001); - assertEquals(0.0d, r.m2, 0.0001); - - // test A-F combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersF.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.25d, r.m1, 0.0001); - assertEquals(0.3333d, r.m2, 0.0001); - - // test A-G combination.firstElement( - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersG.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.25d, r.m1, 0.0001); - assertEquals(0.50d, r.m2, 0.0001); - - // test A-H combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersH.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.25d, r.m1, 0.0001); - assertEquals(1.00d, r.m2, 0.0001); - - // test A-I combination - cursor = new TwinCursor( - mandersA.randomAccess(), - mandersI.randomAccess(), - Views.iterable(mandersAlwaysTrueMask).localizingCursor()); - - r = mc.calculateMandersCorrelation(cursor, - mandersA.randomAccess().get()); - - assertEquals(0.083d, r.m1, 0.001); - assertEquals(0.75d, r.m2, 0.0001); - } - - /** - * This method tests real experimental noisy but - * biologically perfectly colocalized test images, - * using previously calculated autothresholds (.above mode) - * Amongst other things, hopefully it is sensitive to - * choosing the wrong channel to test for above threshold - */ - @Test - public void mandersRealNoisyImagesTest() throws MissingPreconditionException { - - MandersColocalization mrnc = - new MandersColocalization(); - - // test biologically perfect but noisy image coloc combination - // this cast is bad, so use Views.iterable instead. - //Cursor mask = Converters.convert((IterableInterval) positiveCorrelationMaskImage, - Cursor mask = Converters.convert(Views.iterable(positiveCorrelationMaskImage), - new Converter() { - - @Override - public void convert(UnsignedByteType arg0, BitType arg1) { - arg1.set(arg0.get() > 0); - } - }, new BitType()).cursor(); - - TwinCursor twinCursor; - MandersResults r; - // Manually set the thresholds for ch1 and ch2 with the results from a - // Costes Autothreshold using bisection implementation of regression, of the images used - UnsignedByteType thresholdCh1 = new UnsignedByteType(); - thresholdCh1.setInteger(70); - UnsignedByteType thresholdCh2 = new UnsignedByteType(); - thresholdCh2.setInteger(53); - //Set the threshold mode - ThresholdMode tMode; - tMode = ThresholdMode.Above; - // Set the TwinCursor to have the mask image channel, and 2 images. - twinCursor = new TwinCursor( - positiveCorrelationImageCh1.randomAccess(), - positiveCorrelationImageCh2.randomAccess(), - mask); - - // Use the constructor that takes ch1 and ch2 autothresholds and threshold mode. - r = mrnc.calculateMandersCorrelation(twinCursor, thresholdCh1, thresholdCh2, tMode); - - assertEquals(0.705665d, r.m1, 0.000001); - assertEquals(0.724752d, r.m2, 0.000001); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/MaskAndRoiTest.java b/src/test/java/sc/fiji/coloc/tests/MaskAndRoiTest.java deleted file mode 100644 index eee0716..0000000 --- a/src/test/java/sc/fiji/coloc/tests/MaskAndRoiTest.java +++ /dev/null @@ -1,397 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; - -import net.imglib2.Cursor; -import net.imglib2.PredicateCursor; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.predicate.MaskPredicate; -import net.imglib2.predicate.Predicate; -import net.imglib2.roi.RectangleRegionOfInterest; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.gadgets.MaskFactory; - -/** - * This class contains JUnit 4 test cases for the ROI and masks - * implementation. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class MaskAndRoiTest extends ColocalisationTest { - - /** - * Tests if a masked walk over an image refers to the correct data - * by copying the data to a separate image and then compare it with - * the original image data. The position data in the original image - * is calculated based on the ROI offset and the relative position - * in the copied ROI image. - * @throws MissingPreconditionException - */ - @Test - public void maskContentTest() throws MissingPreconditionException { - // load a 3D test image - final RandomAccessibleInterval img = positiveCorrelationImageCh1; - final long[] roiOffset = createRoiOffset(img); - final long[] roiSize = createRoiSize(img); - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - final RandomAccessibleInterval mask = - MaskFactory.createMask(dim, roiOffset, roiSize); - - // create cursor to walk an image with respect to a mask - TwinCursor cursor = new TwinCursor( - img.randomAccess(), img.randomAccess(), - Views.iterable(mask).localizingCursor()); - - // create an image for the "clipped ROI" - ImgFactory maskFactory = - new ArrayImgFactory(); - RandomAccessibleInterval clippedRoiImage = - maskFactory.create( roiSize, new UnsignedByteType() ); // "Clipped ROI" ); - RandomAccess outputCursor = - clippedRoiImage.randomAccess(); - - // copy ROI data to new image - long[] pos = new long[ clippedRoiImage.numDimensions() ]; - while (cursor.hasNext()) { - cursor.fwd(); - cursor.localize(pos); - // shift position by offset - for (int i=0; i roiCopyCursor = - Views.iterable(clippedRoiImage).localizingCursor(); - RandomAccess imgCursor = - img.randomAccess(); - // create variable for summing up and set it to zero - double sum = 0; - pos = new long [ clippedRoiImage.numDimensions() ]; - while (roiCopyCursor.hasNext()) { - roiCopyCursor.fwd(); - roiCopyCursor.localize(pos); - // shift position by offset - for (int i=0; i img = positiveCorrelationImageCh1; - long[] roiOffset = createRoiOffset(img); - long[] roiSize = createRoiSize(img); - long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - RandomAccessibleInterval mask = MaskFactory.createMask(dim, - roiOffset, roiSize); - - // create cursor to walk an image with respect to a mask - final Predicate predicate = new MaskPredicate(); - Cursor roiCursor - = new PredicateCursor( - Views.iterable(mask).localizingCursor(), predicate); - - // test if all visited voxels are "true" - while (roiCursor.hasNext()) { - roiCursor.fwd(); - assertTrue(roiCursor.get().get()); - } - } - - /** - * This test test if a regular mask is created by the MaskFactory - * correctly. First, the dimensions are checked, they must be the - * same as the original images ones. Then it is checked if all - * values in the mask image have the value they should have. For - * a regular ROI this is easy to tell as one can calculate it out - * of the position. - */ - @Test - public void regularMaskCreationTest() throws MissingPreconditionException { - // load a 3D test image - RandomAccessibleInterval img = positiveCorrelationImageCh1; - final long[] roiOffset = createRoiOffset(img); - final long[] roiSize = createRoiSize(img); - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - RandomAccessibleInterval mask = MaskFactory.createMask(dim, - roiOffset, roiSize); - - // is the number of dimensions the same as in the image? - final long[] dimMask = new long[ mask.numDimensions() ]; - mask.dimensions(dimMask); - assertTrue( Arrays.equals(dim, dimMask) ); - - // go through the mask and check if all valid points are in the ROI - long[] pos = new long[ img.numDimensions() ]; - final Cursor cursor = Views.iterable(mask).localizingCursor(); - while ( cursor.hasNext() ) { - cursor.fwd(); - cursor.localize(pos); - // get values in mask image - boolean onInMask = cursor.get().get(); - // calculate value that the current point *should* have - boolean onInROI = true; - for(int i=0; i= roiOffset[i] && pos[i] < (roiOffset[i] + roiSize[i]); - // both values must match - assertTrue(onInMask == onInROI); - } - - /* go once more trough the image wrt. the mask to build a - * bounding box - */ - // create cursor to walk an image with respect to a mask - final Predicate predicate = new MaskPredicate(); - Cursor roiCursor - = new PredicateCursor( - Views.iterable(mask).localizingCursor(), predicate); - long[] min = new long[ mask.numDimensions() ]; - long[] max = new long[ mask.numDimensions() ]; - Arrays.fill(min, Integer.MAX_VALUE); - Arrays.fill(max, Integer.MIN_VALUE); - while (roiCursor.hasNext()) { - roiCursor.fwd(); - roiCursor.localize(pos); - for (int i=0; i max[i]) - max[i] = pos[i]; - } - } - // the bounding box min should equal the ROI offset - assertTrue(Arrays.equals(min, roiOffset)); - // create theoretical bounding box max and check it - long[] roiMax = roiOffset.clone(); - for (int i=0; i img = positiveCorrelationImageCh1; - // first, create an always true mask - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - RandomAccessibleInterval mask = MaskFactory.createMask(dim, true); - final Predicate predicate = new MaskPredicate(); - Cursor cursor - = new PredicateCursor( - Views.iterable(mask).localizingCursor(), predicate); - // iterate over mask and count values - long count = 0; - while (cursor.hasNext()) { - cursor.fwd(); - count++; - assertTrue(cursor.get().get()); - } - assertEquals(ImageStatistics.getNumPixels(mask), count); - - // second, create an always false mask - mask = MaskFactory.createMask(dim, false); - cursor = new PredicateCursor( - Views.iterable(mask).localizingCursor(), predicate); - // iterate over mask and count values - count = 0; - while (cursor.hasNext()) { - cursor.fwd(); - count++; - } - assertEquals(0, count); - } - - /** - * Tests against the implementation of irregular ROIs alias - * masks. Masks can also be produced by mask images open in - * another Fiji window. - * - * This test generates a random black/white noise image and - * uses first itself and then an inverted version of it as - * mask. While iterating over it, the pixel values are - * checked. Is the first version only non-zero values should - * be present, while only zeros should be there in the second - * one. - */ - @Test - public void irregularRoiTest() { - // create a random noise 2D image -- set roiWidh/roiSize accordingly - RandomAccessibleInterval img = - TestImageAccessor.produceSticksNoiseImage(300, 300, 50, 2, 10); - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - - /* first test - using itself as a mask */ - RandomAccessibleInterval mask = MaskFactory.createMask(dim, img); - TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).localizingCursor()); - while (cursor.hasNext()) { - cursor.fwd(); - assertTrue( cursor.getFirst().getInteger() != 0 ); - } - - /* second test - using inverted image */ - RandomAccessibleInterval invImg = - TestImageAccessor.invertImage(img); - RandomAccessibleInterval invMask = - MaskFactory.createMask(dim, invImg); - cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(invMask).localizingCursor()); - while (cursor.hasNext()) { - cursor.fwd(); - assertEquals( 0, cursor.getFirst().getInteger() ); - } - } - - /** - * This test makes sure that a mask that is based on a lower dimension - * image has the correct dimensionality. - */ - @Test - public void irregularRoiDimensionTest() { - // load a 3D test image - RandomAccessibleInterval img = positiveCorrelationImageCh1; - final long width = img.dimension(0); - final long height = img.dimension(1); - final long slices = img.dimension(2); - final long[] dimImg = new long[ img.numDimensions() ]; - img.dimensions(dimImg); - // create a random noise 2D image -- set roiWidh/roiSize accordingly - RandomAccessibleInterval maskSlice = - TestImageAccessor.produceSticksNoiseImage( (int) width, (int) height, 50, 2, 10); - RandomAccessibleInterval mask = - MaskFactory.createMask(dimImg, maskSlice); - final long[] dimMask = new long[ mask.numDimensions() ]; - mask.dimensions(dimMask); - // check the dimensions of the mask - org.junit.Assert.assertArrayEquals(dimImg, dimMask); - // make sure the mask actually got the same content on every slice - final double[] offset = new double[ mask.numDimensions() ]; - Arrays.fill(offset, 0); - double[] size = new double[ mask.numDimensions() ]; - size[0] = width; - size[1] = height; - size[2] = 1; - RandomAccess maskCursor = mask.randomAccess(); - RectangleRegionOfInterest roi = new RectangleRegionOfInterest( offset, size); - Cursor firstSliceCursor = roi.getIterableIntervalOverROI(mask).cursor(); - - final long[] pos = new long[ mask.numDimensions() ]; - while (firstSliceCursor.hasNext()) { - firstSliceCursor.fwd(); - firstSliceCursor.localize(pos); - BitType maskValue = firstSliceCursor.get(); - // go through all slices - for (int i=1; i img = positiveCorrelationImageCh1; - final long[] roiOffset = createRoiOffset(img); - final long[] roiSize = createRoiSize(img); - final long width = img.dimension(0); - final long height = img.dimension(1); - - RandomAccessibleInterval maskImg - = TestImageAccessor.createRectengularMaskImage(width, height, roiOffset, roiSize); - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - RandomAccessibleInterval mask = - MaskFactory.createMask(dim, maskImg); - - TwinCursor cursor = new TwinCursor( - img.randomAccess(), - img.randomAccess(), - Views.iterable(mask).localizingCursor()); - // calculate volume of mask bounding box - long roiVolume = roiSize[0] * roiSize[1] * img.dimension(2); - long count = 0; - while (cursor.hasNext()) { - cursor.fwd(); - count++; - } - - assertEquals(roiVolume, count); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/PearsonsCorrelationTest.java b/src/test/java/sc/fiji/coloc/tests/PearsonsCorrelationTest.java deleted file mode 100644 index 737f456..0000000 --- a/src/test/java/sc/fiji/coloc/tests/PearsonsCorrelationTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; - -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.PearsonsCorrelation; -import sc.fiji.coloc.algorithms.PearsonsCorrelation.Implementation; -import sc.fiji.coloc.gadgets.MaskFactory; - -/** - * This class contains JUnit 4 test cases for the Pearson's correlation - * implementation. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class PearsonsCorrelationTest extends ColocalisationTest { - - /** - * Tests if the fast implementation of Pearson's correlation with two - * zero correlated images produce a Pearson's R value of about zero. - */ - @Test - public void fastPearsonsZeroCorrTest() throws MissingPreconditionException { - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor = new TwinCursor( - zeroCorrelationImageCh1.randomAccess(), - zeroCorrelationImageCh2.randomAccess(), - Views.iterable(zeroCorrelationAlwaysTrueMask).localizingCursor()); - // get the Pearson's value - double pearsonsR = PearsonsCorrelation.fastPearsons(cursor); - // check Pearsons R is close to zero - assertEquals(0.0, pearsonsR, 0.05); - } - - /** - * Tests if the fast implementation of Pearson's correlation with two - * positive correlated images produce a Pearson's R value of about 0.75. - */ - @Test - public void fastPearsonsPositiveCorrTest() throws MissingPreconditionException { - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor = new TwinCursor( - positiveCorrelationImageCh1.randomAccess(), - positiveCorrelationImageCh2.randomAccess(), - Views.iterable(positiveCorrelationAlwaysTrueMask).localizingCursor()); - // get the Pearson's value - double pearsonsR = PearsonsCorrelation.fastPearsons(cursor); - // check Pearsons R is close to 0.75 - assertEquals(0.75, pearsonsR, 0.01); - } - - /** - * Tests if the classic implementation of Pearson's correlation with two - * zero correlated images produce a Pearson's R value of about zero. - */ - @Test - public void classicPearsonsZeroCorrTest() throws MissingPreconditionException { - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor = new TwinCursor( - zeroCorrelationImageCh1.randomAccess(), - zeroCorrelationImageCh2.randomAccess(), - Views.iterable(zeroCorrelationAlwaysTrueMask).localizingCursor()); - // get the Pearson's value - double pearsonsR = PearsonsCorrelation - .classicPearsons(cursor, zeroCorrelationImageCh1Mean, zeroCorrelationImageCh2Mean); - // check Pearsons R is close to zero - assertEquals(0.0, pearsonsR, 0.05); - } - - /** - * Tests if the classic implementation of Pearson's correlation with two - * positive correlated images produce a Pearson's R value of about 0.75. - */ - @Test - public void classicPearsonsPositiveCorrTest() throws MissingPreconditionException { - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor = new TwinCursor( - positiveCorrelationImageCh1.randomAccess(), - positiveCorrelationImageCh2.randomAccess(), - Views.iterable(positiveCorrelationAlwaysTrueMask).localizingCursor()); - // get the Pearson's value - double pearsonsR = PearsonsCorrelation - .classicPearsons(cursor, positiveCorrelationImageCh1Mean, positiveCorrelationImageCh2Mean); - // check Pearsons R is close to 0.75 - assertEquals(0.75, pearsonsR, 0.01); - } - - /** - * Tests Pearson's correlation stays close to zero for image pairs with the same mean and spread - * of randomized pixel values around that mean. - */ - @Test - public void differentMeansTest() throws MissingPreconditionException { - final double initialMean = 0.2; - final double spread = 0.1; - final double[] sigma = new double[] {3.0, 3.0}; - - RandomAccessibleInterval mask = MaskFactory.createMask(new long[] {512, 512}, true); - - for (double mean = initialMean; mean < 1; mean += spread) { - RandomAccessibleInterval ch1 = TestImageAccessor.produceMeanBasedNoiseImage(new FloatType(), - 512, 512, mean, spread, sigma, 0x01234567); - RandomAccessibleInterval ch2 = TestImageAccessor.produceMeanBasedNoiseImage(new FloatType(), - 512, 512, mean, spread, sigma, 0x98765432); - - // create a twin value range cursor that iterates over all pixels of the input data - TwinCursor cursor = new TwinCursor(ch1.randomAccess(), - ch2.randomAccess(), Views.iterable(mask).localizingCursor()); - double resultFast = PearsonsCorrelation.fastPearsons(cursor); - assertEquals(0.0, resultFast, 0.1); - - /* This test will throw Missing PreconsitionException, as the means are the same - * which causes a numerical problem in the classic implementation of Pearson's - * double resultClassic = PearsonsCorrelation.classicPearsons(cursor, mean, mean); - * assertTrue(Math.abs(resultClassic) < 0.1); - */ - } - } - - /** - * The 1993 paper of Manders et. al about colocalization presents an own - * method and testing data for it. For that testing data there are - * Pearson colocalization numbers, too, and these get tested in this test. - * @throws MissingPreconditionException - */ - @Test - public void mandersPaperImagesTest() throws MissingPreconditionException { - PearsonsCorrelation pc = - new PearsonsCorrelation(Implementation.Classic); - double r; - - // test A-A combination - r = pc.calculatePearsons(mandersA, mandersA, mandersAlwaysTrueMask); - assertEquals(1.0d, r, 0.01); - - // test A-B combination - r = pc.calculatePearsons(mandersA, mandersB, mandersAlwaysTrueMask); - assertEquals(0.72d, r, 0.01); - - // test A-C combination - r = pc.calculatePearsons(mandersA, mandersC, mandersAlwaysTrueMask); - assertEquals(0.44d, r, 0.01); - - // test A-D combination - r = pc.calculatePearsons(mandersA, mandersD, mandersAlwaysTrueMask); - assertEquals(0.16d, r, 0.01); - - // test A-E combination - r = pc.calculatePearsons(mandersA, mandersE, mandersAlwaysTrueMask); - assertEquals(-0.12d, r, 0.01); - - // test A-F combination - r = pc.calculatePearsons(mandersA, mandersF, mandersAlwaysTrueMask); - assertEquals(0.22d, r, 0.01); - - // test A-G combination - r = pc.calculatePearsons(mandersA, mandersG, mandersAlwaysTrueMask); - assertEquals(0.30d, r, 0.01); - - // test A-H combination - r = pc.calculatePearsons(mandersA, mandersH, mandersAlwaysTrueMask); - assertEquals(0.48d, r, 0.01); - - // test A-I combination - r = pc.calculatePearsons(mandersA, mandersI, mandersAlwaysTrueMask); - assertEquals(0.23d, r, 0.01); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/SpearmanRankTest.java b/src/test/java/sc/fiji/coloc/tests/SpearmanRankTest.java deleted file mode 100644 index d340088..0000000 --- a/src/test/java/sc/fiji/coloc/tests/SpearmanRankTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import net.imglib2.TwinCursor; -import net.imglib2.type.numeric.integer.UnsignedByteType; -import net.imglib2.view.Views; - -import org.junit.Test; - -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.algorithms.SpearmanRankCorrelation; - -/** - * This class contains JUnit 4 test cases for the calculation of - * Spearman's Rank Correlation (rho). - * - * @author Leonardo Guizzetti - */ -public class SpearmanRankTest extends ColocalisationTest { - - /** - * Checks Spearman's Rank Correlation rho for positive correlated images. - */ - @Test - public void spearmanPositiveCorrTest() throws MissingPreconditionException { - TwinCursor cursor = new TwinCursor( - positiveCorrelationImageCh1.randomAccess(), - positiveCorrelationImageCh2.randomAccess(), - Views.iterable(positiveCorrelationAlwaysTrueMask).localizingCursor()); - // calculate Spearman's Rank rho value - double rho = new SpearmanRankCorrelation().calculateSpearmanRank(cursor); - // Rho value = 0.5463... - assertTrue(rho > 0.546 && rho < 0.547); - } - - /** - * Checks Spearman's Rank Correlation value for zero correlated images. The rho value - * should be about zero. - */ - @Test - public void spearmanZeroCorrTest() throws MissingPreconditionException { - TwinCursor cursor = new TwinCursor( - zeroCorrelationImageCh1.randomAccess(), - zeroCorrelationImageCh2.randomAccess(), - Views.iterable(zeroCorrelationAlwaysTrueMask).localizingCursor()); - // calculate Spearman's Rank rho value - double rho = new SpearmanRankCorrelation().calculateSpearmanRank(cursor); - // Rho value = -0.11... - assertTrue(Math.abs(rho) < 0.012); - } - - /** - * Checks Spearman's Rank Correlation value for slightly negative correlated synthetic data. - * - */ - @Test - public void statisticsTest() throws MissingPreconditionException { - - double[][] data = new double[][] { - {1,113}, - {2,43}, - {3,11}, - {6,86}, - {5,59}, - {8,47}, - {4,92}, - {0,152}, - {6,23}, - {4,9}, - {7,33}, - {3,69}, - {2,75}, - {9,135}, - {3,30} - }; - int n = data.length; - - final SpearmanRankCorrelation src = new SpearmanRankCorrelation(); - - /* - * Check the arithmetic for the rho calculation. - * Rho is exactly -0.1743 (to 4 decimal points) using the - * exact calculation for Spearman's rho as implemented here. - */ - double rho = src.calculateSpearmanRank(data); - assertEquals(-0.1743, rho, 0.001); - - // check the degrees of freedom calculation ( df = n - 2 ) - int df = 0; - df = src.getSpearmanDF(n); - assertEquals(df, n - 2); - - // check the t-statistic calculation ( t = rho * sqrt( df / (1-rho^2) ) ) - // The t-stat = -0.6382 - double tstat = 0.0; - tstat = src.getTStatistic(rho, n); - assertEquals(-0.6382, tstat, 0.001); - } - - /** - * Checks Spearman's Rank Correlation value for synthetic test image. - * This tests the same dataset as the statisticsTest() but tests reading in image - * data, the rank transform, and the calling of the statistics calculation methods. - */ - @Test - public void spearmanSyntheticNegCorrTest() throws MissingPreconditionException { - TwinCursor cursor = new TwinCursor( - syntheticNegativeCorrelationImageCh1.randomAccess(), - syntheticNegativeCorrelationImageCh2.randomAccess(), - Views.iterable(syntheticNegativeCorrelationAlwaysTrueMask).localizingCursor()); - - // calculate Spearman's Rank rho value - double rho = new SpearmanRankCorrelation().calculateSpearmanRank(cursor); - assertTrue((rho > -0.178) && (rho < -0.173)); - } - -} diff --git a/src/test/java/sc/fiji/coloc/tests/StatisticsTest.java b/src/test/java/sc/fiji/coloc/tests/StatisticsTest.java deleted file mode 100644 index 292431d..0000000 --- a/src/test/java/sc/fiji/coloc/tests/StatisticsTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.List; - -import org.junit.Test; - -import sc.fiji.coloc.gadgets.Statistics; - -/** - * This class contains JUnit 4 test cases for the implementation - * of different statistics methods. - * - * @author Tom Kazimiers - */ -public class StatisticsTest { - /** - * Test the error function. Test values have been taken from: - * http://en.wikipedia.org/wiki/Error_function - */ - @Test - public void erfTest() { - // erf(0) = 0 - double erf = Statistics.erf(0.0); - assertTrue( Math.abs(erf) < 0.0001); - // erf(0.5) = 0.5204999 - erf = Statistics.erf(0.5); - assertTrue( Math.abs(erf - 0.5204999) < 0.0001); - // erf(1.0) = 0.8427008 - erf = Statistics.erf(1.0); - assertTrue( Math.abs(erf - 0.8427008) < 0.0001); - // erf(-0.5) = -0.5204999 - erf = Statistics.erf(-0.5); - assertTrue( Math.abs(erf + 0.5204999) < 0.0001); - // erf(-1.0) = -0.8427008 - erf = Statistics.erf(-1.0); - assertTrue( Math.abs(erf + 0.8427008) < 0.0001); - } - - /** - * Test the cumulative distribution function (phi) for the - * standard normal distribution. - */ - @Test - public void phiTest() { - // phi(0) = 0.5 - double phi = Statistics.phi(0.0); - assertTrue( Math.abs(phi - 0.5) < 0.0001 ); - // phi(-1) = 0.158655 - phi = Statistics.phi(-1.0); - assertTrue( Math.abs(phi - 0.158655) < 0.0001 ); - // phi(0.5) = 0.691462 - phi = Statistics.phi(0.5); - assertTrue( Math.abs(phi - 0.691462) < 0.0001 ); - // phi(1.960) = 0.975002 - phi = Statistics.phi(1.960); - assertTrue( Math.abs(phi - 0.975002) < 0.0001 ); - } - - /** - * Test the cumulative distribution function (phi) for the - * normal distribution (based on mean and standard derivation). - */ - @Test - public void phiDifferentDistributionTest() { - // phi(0.5, 0, 1) = 0.691462 - double phi = Statistics.phi(0.5, 0.0, 1.0); - assertTrue( Math.abs(phi - 0.691462) < 0.0001 ); - // phi(0.5, 20, 12) = 0.052081 - phi = Statistics.phi(0.5, 20, 12); - assertTrue( Math.abs(phi - 0.052081) < 0.0001 ); - // phi(-1, 42, 33) = 0.096282 - phi = Statistics.phi(-1, 42, 33); - assertTrue( Math.abs(phi - 0.096282) < 0.0001 ); - } - - /** - * Tests the calculation of the standard deviation of a list - * of values. - */ - @Test - public void stdDeviationTest() { - /* the standard deviation of the list - * [1, 3, 4, 6, 9, 19] is 6.48074069 - */ - List values = Arrays.asList( new Double[] {1.0, 3.0, 4.0, 6.0, 9.0, 19.0} ); - double sd = Statistics.stdDeviation(values); - assertTrue( Math.abs( sd - 6.48074069 ) < 0.0001); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/TestImageAccessor.java b/src/test/java/sc/fiji/coloc/tests/TestImageAccessor.java deleted file mode 100644 index 64a6f6d..0000000 --- a/src/test/java/sc/fiji/coloc/tests/TestImageAccessor.java +++ /dev/null @@ -1,445 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import static org.junit.Assume.assumeNotNull; - -import ij.ImagePlus; -import ij.gui.NewImage; -import ij.gui.Roi; -import ij.io.Opener; -import ij.process.ImageProcessor; - -import java.awt.Color; -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Random; - -import net.imglib2.Cursor; -import net.imglib2.Interval; -import net.imglib2.Localizable; -import net.imglib2.Point; -import net.imglib2.RandomAccess; -import net.imglib2.RandomAccessible; -import net.imglib2.RandomAccessibleInterval; -import net.imglib2.TwinCursor; -import net.imglib2.algorithm.gauss.Gauss; -import net.imglib2.algorithm.math.ImageStatistics; -import net.imglib2.img.ImagePlusAdapter; -import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; -import net.imglib2.img.array.ArrayImgFactory; -import net.imglib2.type.NativeType; -import net.imglib2.type.logic.BitType; -import net.imglib2.type.numeric.RealType; -import net.imglib2.type.numeric.real.FloatType; -import net.imglib2.view.Views; - -import sc.fiji.coloc.algorithms.MissingPreconditionException; -import sc.fiji.coloc.gadgets.MaskFactory; - -/** - * A class containing some testing helper methods. It allows - * to open Tiffs from within the Jar file and can generate noise - * images. - * - * @author Dan White - * @author Tom Kazimiers - */ -public class TestImageAccessor { - /* a static opener for opening images without the - * need for creating every time a new opener - */ - static Opener opener = new Opener(); - - /** - * Loads a Tiff file from within the jar. The given path is treated - * as relative to this tests-package (i.e. "Data/test.tiff" refers - * to the test.tiff in sub-folder Data). - * - * @param The wanted output type. - * @param relPath The relative path to the Tiff file. - * @return The file as ImgLib image. - */ - public static & NativeType> RandomAccessibleInterval loadTiffFromJar(String relPath) { - InputStream is = TestImageAccessor.class.getResourceAsStream(relPath); - BufferedInputStream bis = new BufferedInputStream(is); - - ImagePlus imp = opener.openTiff(bis, "The Test Image"); - assumeNotNull(imp); - return ImagePlusAdapter.wrap(imp); - } - - /** - * Loads a Tiff file from within the jar to use as a mask Cursor. - * So we use Img which has a cursor() method. - * The given path is treated - * as relative to this tests-package (i.e. "Data/test.tiff" refers - * to the test.tiff in sub-folder Data). - * - * @param The wanted output type. - * @param relPath The relative path to the Tiff file. - * @return The file as ImgLib image. - */ - public static & NativeType> Img loadTiffFromJarAsImg(String relPath) { - InputStream is = TestImageAccessor.class.getResourceAsStream(relPath); - BufferedInputStream bis = new BufferedInputStream(is); - - ImagePlus imp = opener.openTiff(bis, "The Test Image"); - assumeNotNull(imp); - return ImagePlusAdapter.wrap(imp); - } - - /** - * Creates a noisy image that is created by repeatedly adding points - * with random intensity to the canvas. That way it tries to mimic the - * way a microscope produces images. This convenience method uses the - * default values of a point size of 3.0 and produces 5000 points. - * After the creation the image is smoothed with a sigma of one in each - * direction. - * - * @param The wanted output type. - * @param width The image width. - * @param height The image height. - * @return The noise image. - */ - public static & NativeType> RandomAccessibleInterval produceNoiseImageSmoothed(T type, int width, int height) { - return produceNoiseImageSmoothed(type, width, height, 3.0f, 5000, new double[] {1.0,1.0}); - } - - /** - * Creates a noisy image that is created by repeatedly adding points - * with random intensity to the canvas. That way it tries to mimic the - * way a microscope produces images. - * - * @param The wanted output type. - * @param width The image width. - * @param height The image height. - * @param dotSize The size of the dots. - * @param numDots The number of dots. - * @param smoothingSigma The two dimensional sigma for smoothing. - * @return The noise image. - */ - public static & NativeType> RandomAccessibleInterval produceNoiseImage(int width, - int height, float dotSize, int numDots) { - /* For now (probably until ImageJ2 is out) we use an - * ImageJ image to draw circles. - */ - int options = NewImage.FILL_BLACK + NewImage.CHECK_AVAILABLE_MEMORY; - ImagePlus img = NewImage.createByteImage("Noise", width, height, 1, options); - ImageProcessor imp = img.getProcessor(); - - float dotRadius = dotSize * 0.5f; - int dotIntSize = (int) dotSize; - - for (int i=0; i < numDots; i++) { - int x = (int) (Math.random() * width - dotRadius); - int y = (int) (Math.random() * height - dotRadius); - imp.setColor(Color.WHITE); - imp.fillOval(x, y, dotIntSize, dotIntSize); - } - // we changed the data, so update it - img.updateImage(); - // create the new image - RandomAccessibleInterval noiseImage = ImagePlusAdapter.wrap(img); - - return noiseImage; - } - - public static & NativeType> RandomAccessibleInterval produceNoiseImageSmoothed(T type, int width, - int height, float dotSize, int numDots, double[] smoothingSigma) { - RandomAccessibleInterval noiseImage = produceNoiseImage(width, height, dotSize, numDots); - - return gaussianSmooth(noiseImage, smoothingSigma); - } - - /** - * This method creates a noise image that has a specified mean. - * Every pixel has a value uniformly distributed around mean with - * the maximum spread specified. - * - * @return a new noise image - * @throws MissingPreconditionException if specified means and spreads are not valid - */ - public static & NativeType> RandomAccessibleInterval produceMeanBasedNoiseImage(T type, int width, - int height, double mean, double spread, double[] smoothingSigma, long seed) throws MissingPreconditionException { - if (mean < spread || (mean + spread) > type.getMaxValue()) { - throw new MissingPreconditionException("Mean must be larger than spread, and mean plus spread must be smaller than max of the type"); - } - // create the new image - ImgFactory imgFactory = new ArrayImgFactory(); - RandomAccessibleInterval noiseImage = imgFactory.create( new int[] {width, height}, type); // "Noise image"); - - Random r = new Random(seed); - for (T value : Views.iterable(noiseImage)) { - value.setReal( mean + ( (r.nextDouble() - 0.5) * spread ) ); - } - - return gaussianSmooth(noiseImage, smoothingSigma); - } - - /** - * This method creates a noise image that is made of many little - * sticks oriented in a random direction. How many of them and - * what the length of them are can be specified. - * - * @return a new noise image that is not smoothed - */ - public static & NativeType> RandomAccessibleInterval produceSticksNoiseImage(int width, - int height, int numSticks, int lineWidth, double maxLength) { - /* For now (probably until ImageJ2 is out) we use an - * ImageJ image to draw lines. - */ - int options = NewImage.FILL_BLACK + NewImage.CHECK_AVAILABLE_MEMORY; - ImagePlus img = NewImage.createByteImage("Noise", width, height, 1, options); - ImageProcessor imp = img.getProcessor(); - imp.setColor(Color.WHITE); - imp.setLineWidth(lineWidth); - - for (int i=0; i < numSticks; i++) { - // find random starting point - int x = (int) (Math.random() * width); - int y = (int) (Math.random() * height); - // create random stick length and direction - double length = Math.random() * maxLength; - double angle = Math.random() * 2 * Math.PI; - // calculate random point on circle, for the direction - int destX = x + (int) (length * Math.cos(angle)); - int destY = y + (int) (length * Math.sin(angle)); - // now draw the line - imp.drawLine(x, y, destX, destY); - } - // we changed the data, so update it - img.updateImage(); - - return ImagePlusAdapter.wrap(img); - } - - /** - * This method creates a smoothed noise image that is made of - * many little sticks oriented in a random direction. How many - * of them and what the length of them are can be specified. - * - * @return a new noise image that is smoothed - */ - public static & NativeType> RandomAccessibleInterval produceSticksNoiseImageSmoothed(T type, int width, - int height, int numSticks, int lineWidth, double maxLength, double[] smoothingSigma) { - - RandomAccessibleInterval noiseImage = produceSticksNoiseImage(width, height, numSticks, lineWidth, maxLength); - - return gaussianSmooth(noiseImage, smoothingSigma); - } - - /** - * Generates a Perlin noise image. It is based on Ken Perlin's - * reference implementation (ImprovedNoise class) and a small - * bit of Kas Thomas' sample code (http://asserttrue.blogspot.com/). - */ - public static & NativeType> RandomAccessibleInterval producePerlinNoiseImage(T type, int width, - int height, double z, double scale) { - // create the new image - ImgFactory imgFactory = new ArrayImgFactory(); - RandomAccessibleInterval noiseImage = imgFactory.create( new int[] {width, height}, type); - Cursor noiseCursor = Views.iterable(noiseImage).localizingCursor(); - - double xOffset = Math.random() * (width*width); - double yOffset = Math.random() * (height*height); - - while (noiseCursor.hasNext()) { - noiseCursor.fwd(); - double x = (noiseCursor.getDoublePosition(0) + xOffset) * scale; - double y = (noiseCursor.getDoublePosition(1) + yOffset) * scale; - - float t = (float)ImprovedNoise.noise( x, y, z); - - // ImprovedNoise.noise returns a float in the range [-1..1], - // whereas we want a float in the range [0..1], so: - t = (1 + t) * 0.5f; - - noiseCursor.get().setReal(t); - } - - //return gaussianSmooth(noiseImage, imgFactory, smoothingSigma); - return noiseImage; - } - - /** - * Gaussian Smooth of the input image using intermediate float format. - * @param - * @param img - * @param sigma - * @return - */ - public static & NativeType> RandomAccessibleInterval gaussianSmooth( - RandomAccessibleInterval img, double[] sigma) { - Interval interval = Views.iterable(img); - - ImgFactory outputFactory = new ArrayImgFactory(); - final long[] dim = new long[ img.numDimensions() ]; - img.dimensions(dim); - RandomAccessibleInterval output = outputFactory.create( dim, - img.randomAccess().get().createVariable() ); - - final long[] pos = new long[ img.numDimensions() ]; - Arrays.fill(pos, 0); - Localizable origin = new Point(pos); - - ImgFactory tempFactory = new ArrayImgFactory(); - RandomAccessible input = Views.extendMirrorSingle(img); - Gauss.inFloat(sigma, input, interval, output, origin, tempFactory); - - return output; - } - - /** - * Inverts an image. - * - * @param The images data type. - * @param image The image to convert. - * @return The inverted image. - */ - public static & NativeType> RandomAccessibleInterval invertImage( - RandomAccessibleInterval image) { - Cursor imgCursor = Views.iterable(image).localizingCursor(); - // invert the image - long[] dim = new long[ image.numDimensions() ]; - image.dimensions(dim); - ArrayImgFactory imgFactory = new ArrayImgFactory(); - RandomAccessibleInterval invImg = imgFactory.create( - dim, image.randomAccess().get().createVariable() ); // "Inverted " + image.getName()); - RandomAccess invCursor = invImg.randomAccess(); - - while (imgCursor.hasNext()) { - imgCursor.fwd(); - invCursor.setPosition(imgCursor); - invCursor.get().setReal( imgCursor.get().getMaxValue() - imgCursor.get().getRealDouble() ); - } - - return invImg; - } - - /** - * Converts an arbitrary image to a black/white version of it. - * All image data lower or equal 0.5 times the maximum value - * of the image type will get black, the rest will turn white. - */ - public static & NativeType> RandomAccessibleInterval makeBinaryImage( - RandomAccessibleInterval image) { - T binSplitValue = image.randomAccess().get(); - binSplitValue.setReal( binSplitValue.getMaxValue() * 0.5 ); - return TestImageAccessor.makeBinaryImage(image, binSplitValue); - } - - /** - * Converts an arbitrary image to a black/white version of it. - * All image data lower or equal the splitValue will get black, - * the rest will turn white. - */ - public static & NativeType> RandomAccessibleInterval makeBinaryImage( - RandomAccessibleInterval image, T splitValue) { - Cursor imgCursor = Views.iterable(image).localizingCursor(); - // make a new image of the same type, but binary - long[] dim = new long[ image.numDimensions() ]; - image.dimensions(dim); - ArrayImgFactory imgFactory = new ArrayImgFactory(); - RandomAccessibleInterval binImg = imgFactory.create( dim, - image.randomAccess().get().createVariable() ); // "Binary image of " + image.getName()); - RandomAccess invCursor = binImg.randomAccess(); - - while (imgCursor.hasNext()) { - imgCursor.fwd(); - invCursor.setPosition(imgCursor); - T currentValue = invCursor.get(); - if (currentValue.compareTo(splitValue) > 0) - currentValue.setReal( currentValue.getMaxValue() ); - else - currentValue.setZero(); - } - - return binImg; - } - - /** - * A method to combine a foreground image and a background image. - * If data on the foreground image is above zero, it will be - * placed on the background. While doing that, the image data from - * the foreground is scaled to be in range of the background. - */ - public static > void combineImages(RandomAccessibleInterval background, - RandomAccessibleInterval foreground) { - final long[] dim = new long[ background.numDimensions() ]; - background.dimensions(dim); - RandomAccessibleInterval alwaysTrueMask = MaskFactory.createMask(dim, true); - TwinCursor cursor = new TwinCursor( - background.randomAccess(), - foreground.randomAccess(), - Views.iterable(alwaysTrueMask).localizingCursor()); - // find a scaling factor for scale forground range into background - double bgMin = ImageStatistics.getImageMin(background).getRealDouble(); - double bgMax = ImageStatistics.getImageMax(background).getRealDouble(); - double fgMin = ImageStatistics.getImageMin(foreground).getRealDouble(); - double fgMax = ImageStatistics.getImageMax(foreground).getRealDouble(); - - double scaling = (bgMax - bgMin ) / (fgMax - fgMin); - // iterate over both images - while (cursor.hasNext()) { - cursor.fwd(); - T bgData = cursor.getFirst(); - double fgData = cursor.getSecond().getRealDouble() * scaling; - if (fgData > 0.01) { - /* if the foreground data is above zero, copy - * it to the background. - */ - bgData.setReal(fgData); - } - } - } - - /** - * Creates a mask image with a black background and a white - * rectangular foreground. - * - * @param width The width of the result image. - * @param height The height of the result image. - * @param offset The offset of the rectangular mask. - * @param size The size of the rectangular mask. - * @return A black image with a white rectangle on it. - */ - public static & NativeType> RandomAccessibleInterval createRectengularMaskImage( - long width, long height, long[] offset, long[] size) { - /* For now (probably until ImageJ2 is out) we use an - * ImageJ image to draw lines. - */ - int options = NewImage.FILL_BLACK + NewImage.CHECK_AVAILABLE_MEMORY; - ImagePlus img = NewImage.createByteImage("Noise", (int)width, (int)height, 1, options); - ImageProcessor imp = img.getProcessor(); - imp.setColor(Color.WHITE); - Roi rect = new Roi(offset[0], offset[1], size[0], size[1]); - - imp.fill(rect); - // we changed the data, so update it - img.updateImage(); - - return ImagePlusAdapter.wrap(img); - } -} diff --git a/src/test/java/sc/fiji/coloc/tests/TestInteractively.java b/src/test/java/sc/fiji/coloc/tests/TestInteractively.java deleted file mode 100644 index 0b5e1ee..0000000 --- a/src/test/java/sc/fiji/coloc/tests/TestInteractively.java +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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 sc.fiji.coloc.tests; - -import fiji.Debug; - -public class TestInteractively { - - public static void main(String[] args) { - // dummy call: initialize debug session - Debug.run("Close All", ""); - final String image1 = "colocsample1b-green.tif"; - final String image2 = "colocsample1b-red.tif"; - String testsDataDir = System.getProperty("plugins.dir") + "/../src/test/resources/"; - Debug.run("Open...", "open=" + testsDataDir + image1); - Debug.run("Open...", "open=" + testsDataDir + image2); - Debug.run("Coloc 2", - "channel_1=" + image1 + " channel_2=" + image2 + " roi_or_mask= " - + "li_histogram_channel_1 " - + "li_histogram_channel_2 " - + "li_icq " - + "spearman's_rank_correlation " - + "manders'_correlation " - + "kendall's_tau_rank_correlation " - + "2d_instensity_histogram " - + "costes'_significance_test " - + "psf=3 " - + "costes_randomisations=10" - ); - } -} diff --git a/src/test/resources/SineXCosY.ijm b/src/test/resources/SineXCosY.ijm deleted file mode 100644 index 922af5e..0000000 --- a/src/test/resources/SineXCosY.ijm +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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% - */ -// This macro uses the Process>Math>Macro command -// to create a synthetic image. -// The formula that generates the image comes from -// MathMacroDemo macro from imageJ example macros page -// http://rsbweb.nih.gov/ij/macros/examples/MathMacroDemo.txt -// The image is a sin wave in x and a cos wave in y, -// giving a regular grid of blobs that look a bit like -// diffraction limited images of sub resolution objects - -// get a new image to write into - it is 32 bit for high precision -run("Hyperstack...", "title=sine type=32-bit display=Grayscale width=1000 height=1000 channels=1 slices=1 frames=1"); - -// Macro... is the Process>Math>Macro command -// for making images from expresions. -// Here is the string expression for making the image -eqn = "v = (254/2) + ( (254/2) * (sin(0.4*(x+1)) * sin(0.4*(y+1)) ) )"; -// why cant i just do: -//"code=[Eqn]" -//string concatenation or something i guess? - -//Now run the Process>Math>Macro command with the expression -run("Macro...", "code=["+eqn+"]"); - -// -setMinAndMax(0.0, 255.0); -run("8-bit"); diff --git a/src/test/resources/colocsample1b-green.tif b/src/test/resources/colocsample1b-green.tif deleted file mode 100644 index eee9d11..0000000 Binary files a/src/test/resources/colocsample1b-green.tif and /dev/null differ diff --git a/src/test/resources/colocsample1b-mask.tif b/src/test/resources/colocsample1b-mask.tif deleted file mode 100644 index d03ab6a..0000000 Binary files a/src/test/resources/colocsample1b-mask.tif and /dev/null differ diff --git a/src/test/resources/colocsample1b-red.tif b/src/test/resources/colocsample1b-red.tif deleted file mode 100644 index bac42dd..0000000 Binary files a/src/test/resources/colocsample1b-red.tif and /dev/null differ diff --git a/src/test/resources/greenZstack.tif b/src/test/resources/greenZstack.tif deleted file mode 100644 index 7a36caa..0000000 Binary files a/src/test/resources/greenZstack.tif and /dev/null differ diff --git a/src/test/resources/high_random_overlap1.tif b/src/test/resources/high_random_overlap1.tif deleted file mode 100644 index cbd32f2..0000000 Binary files a/src/test/resources/high_random_overlap1.tif and /dev/null differ diff --git a/src/test/resources/high_random_overlap2.tif b/src/test/resources/high_random_overlap2.tif deleted file mode 100644 index 131f69a..0000000 Binary files a/src/test/resources/high_random_overlap2.tif and /dev/null differ diff --git a/src/test/resources/mandersA.tiff b/src/test/resources/mandersA.tiff deleted file mode 100644 index 379ecbd..0000000 Binary files a/src/test/resources/mandersA.tiff and /dev/null differ diff --git a/src/test/resources/mandersB.tiff b/src/test/resources/mandersB.tiff deleted file mode 100644 index 0428440..0000000 Binary files a/src/test/resources/mandersB.tiff and /dev/null differ diff --git a/src/test/resources/mandersC.tiff b/src/test/resources/mandersC.tiff deleted file mode 100644 index 90e0a86..0000000 Binary files a/src/test/resources/mandersC.tiff and /dev/null differ diff --git a/src/test/resources/mandersD.tiff b/src/test/resources/mandersD.tiff deleted file mode 100644 index 4b6579b..0000000 Binary files a/src/test/resources/mandersD.tiff and /dev/null differ diff --git a/src/test/resources/mandersE.tiff b/src/test/resources/mandersE.tiff deleted file mode 100644 index 7f463c4..0000000 Binary files a/src/test/resources/mandersE.tiff and /dev/null differ diff --git a/src/test/resources/mandersF.tiff b/src/test/resources/mandersF.tiff deleted file mode 100644 index a144555..0000000 Binary files a/src/test/resources/mandersF.tiff and /dev/null differ diff --git a/src/test/resources/mandersG.tiff b/src/test/resources/mandersG.tiff deleted file mode 100644 index 3fbe16e..0000000 Binary files a/src/test/resources/mandersG.tiff and /dev/null differ diff --git a/src/test/resources/mandersH.tiff b/src/test/resources/mandersH.tiff deleted file mode 100644 index 01fba9b..0000000 Binary files a/src/test/resources/mandersH.tiff and /dev/null differ diff --git a/src/test/resources/mandersI.tiff b/src/test/resources/mandersI.tiff deleted file mode 100644 index ab8c7c8..0000000 Binary files a/src/test/resources/mandersI.tiff and /dev/null differ diff --git a/src/test/resources/random-dots-smoothed.ijm b/src/test/resources/random-dots-smoothed.ijm deleted file mode 100644 index 254f023..0000000 --- a/src/test/resources/random-dots-smoothed.ijm +++ /dev/null @@ -1,36 +0,0 @@ -/*- - * #%L - * Fiji's plugin for colocalization analysis. - * %% - * Copyright (C) 2009 - 2017 Fiji 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 3 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% - */ -// This macro draws randomly positioned dots on the active -// image in the current foreground color, then gaussian smooths them. - -dotSize = 3; -numberOfDots = 5000; - width = getWidth(); - height = getHeight(); - for (i=0; i