package gdsc.smlm.ij.results;
import java.awt.Rectangle;
import java.util.Arrays;
import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.Well19937c;
import org.junit.Assert;
import org.junit.Test;
import gdsc.core.utils.TurboList;
import gdsc.smlm.function.gaussian.Gaussian2DFunction;
import gdsc.smlm.results.PeakResult;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
/**
* Test the IJImagePeakResults functionality.
*/
public class IJImagePeakResultsTest
{
//private RandomGenerator rand = new Well19937c(System.currentTimeMillis() + System.identityHashCode(this));
private RandomGenerator rand = new Well19937c(30051977);
private static final String title = "Test";
Rectangle bounds = new Rectangle(0, 0, 3, 5);
@Test
public void canAddToSinglePixels()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
add(fp, r, 1, 1, 1);
add(fp, r, 1, 2, 4);
add(fp, r, 0, 1, 2);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canAddToSinglePixelsWithInvalidPositions()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
add(fp, r, 1, 1, 1);
add(fp, r, 1, 2, 4);
add(fp, r, 0, 1, 2);
for (int x : new int[] { -1, 0, 1, bounds.width, bounds.width + 1 })
for (int y : new int[] { -1, 0, 1, bounds.height, bounds.height + 1 })
add(fp, r, x, y, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canAddToZeroSizeImage()
{
Rectangle zeroBounds = new Rectangle();
canAddToZeroSizeImage(zeroBounds);
zeroBounds.width = 1;
canAddToZeroSizeImage(zeroBounds);
zeroBounds.width = 0;
zeroBounds.height = 1;
canAddToZeroSizeImage(zeroBounds);
zeroBounds.width = -1;
zeroBounds.height = -1;
canAddToZeroSizeImage(zeroBounds);
}
private static void canAddToZeroSizeImage(Rectangle bounds)
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
begin(r);
for (int x : new int[] { -1, 0, 1, bounds.width, bounds.width + 1 })
for (int y : new int[] { -1, 0, 1, bounds.height, bounds.height + 1 })
r.add(x, y, 1);
r.end();
float[] expecteds = new float[1];
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
private void add(FloatProcessor fp, IJImagePeakResults r, int x, int y, float value)
{
addValue(r, x, y, value);
fp.putPixelValue(x, y, fp.getPixelValue(x, y) + value);
}
@Test
public void canInterpolateInMiddleOfPixel()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 1.5f, 1);
fp.putPixelValue(1, 1, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInXAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1f, 1.5f, 2);
fp.putPixelValue(0, 1, 1);
fp.putPixelValue(1, 1, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInXAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 2f, 1.5f, 2);
fp.putPixelValue(1, 1, 1);
fp.putPixelValue(2, 1, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInYAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 1f, 2);
fp.putPixelValue(1, 0, 1);
fp.putPixelValue(1, 1, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInYAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 2f, 2);
fp.putPixelValue(1, 1, 1);
fp.putPixelValue(1, 2, 1);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInX()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.25f, 1.5f, 2);
fp.putPixelValue(0, 1, 0.5f);
fp.putPixelValue(1, 1, 1.5f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInX()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.75f, 1.5f, 2);
fp.putPixelValue(1, 1, 1.5f);
fp.putPixelValue(2, 1, 0.5f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInY()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 1.25f, 2);
fp.putPixelValue(1, 0, 0.5f);
fp.putPixelValue(1, 1, 1.5f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInY()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 1.75f, 2);
fp.putPixelValue(1, 1, 1.5f);
fp.putPixelValue(1, 2, 0.5f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInXYAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1f, 1f, 4);
fp.putPixelValue(0, 0, 1f);
fp.putPixelValue(0, 1, 1f);
fp.putPixelValue(1, 0, 1f);
fp.putPixelValue(1, 1, 1f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInXYAtPixelEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 2f, 2f, 4);
fp.putPixelValue(1, 1, 1f);
fp.putPixelValue(2, 1, 1f);
fp.putPixelValue(1, 2, 1f);
fp.putPixelValue(2, 2, 1f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateDownInXY()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.25f, 1.25f, 1);
fp.putPixelValue(0, 0, 0.25f * 0.25f);
fp.putPixelValue(0, 1, 0.75f * 0.25f);
fp.putPixelValue(1, 0, 0.75f * 0.25f);
fp.putPixelValue(1, 1, 0.75f * 0.75f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canInterpolateUpInXY()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.75f, 1.75f, 1);
fp.putPixelValue(1, 1, 0.75f * 0.75f);
fp.putPixelValue(2, 1, 0.75f * 0.25f);
fp.putPixelValue(1, 2, 0.75f * 0.25f);
fp.putPixelValue(2, 2, 0.25f * 0.25f);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void noInterpolateDownInXAtImageEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 0.5f, 1.5f, 2);
fp.putPixelValue(0, 1, 2);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void noInterpolateUpInXAtImageEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 2.5f, 1.5f, 2);
fp.putPixelValue(2, 1, 2);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void noInterpolateDownInYAtImageEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 0.5f, 2);
fp.putPixelValue(1, 0, 2);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void noInterpolateUpInYAtImageEdge()
{
IJImagePeakResults r = new IJImagePeakResults(title, bounds, 1);
r.setDisplayFlags(IJImagePeakResults.DISPLAY_WEIGHTED);
FloatProcessor fp = new FloatProcessor(bounds.width, bounds.height);
begin(r);
addValue(r, 1.5f, 2.5f, 2);
fp.putPixelValue(1, 2, 2);
r.end();
float[] expecteds = getImage(fp);
float[] actuals = getImage(r);
Assert.assertArrayEquals(expecteds, actuals, 0);
}
@Test
public void canAddUsingDifferentMethods()
{
canAddUsingDifferentMethods(0);
}
@Test
public void canAddUsingDifferentMethodsEqualized()
{
canAddUsingDifferentMethods(IJImagePeakResults.DISPLAY_EQUALIZED);
}
@Test
public void canAddUsingDifferentMethodsEqualizedWeighted()
{
canAddUsingDifferentMethods(IJImagePeakResults.DISPLAY_EQUALIZED | IJImagePeakResults.DISPLAY_WEIGHTED);
}
@Test
public void canAddUsingDifferentMethodsMax()
{
canAddUsingDifferentMethods(IJImagePeakResults.DISPLAY_MAX);
}
@Test
public void canAddUsingDifferentMethodsReplace()
{
canAddUsingDifferentMethods(IJImagePeakResults.DISPLAY_REPLACE);
}
@Test
public void canAddUsingDifferentMethodsWeighted()
{
canAddUsingDifferentMethods(IJImagePeakResults.DISPLAY_WEIGHTED);
}
private void canAddUsingDifferentMethods(int displayFlags)
{
displayFlags |= IJImagePeakResults.DISPLAY_SIGNAL;
IJImagePeakResults[] r = new IJImagePeakResults[8];
for (int i = 0; i < r.length; i++)
{
r[i] = new IJImagePeakResults(title + i, bounds, 1);
r[i].setDisplayFlags(displayFlags);
begin(r[i]);
}
int size = 20;
int[] t = new int[size];
float[] x = new float[size];
float[] y = new float[size];
float[] v = new float[size];
for (int i = 0; i < size; i++)
{
t[i] = i;
x[i] = (rand.nextFloat() * bounds.width);
y[i] = (rand.nextFloat() * bounds.height);
v[i] = (rand.nextFloat());
addPeakResult(r[0], x[i], y[i], v[i]);
addPeakResult(r[1], t[i], x[i], y[i], v[i]);
addValue(r[2], x[i], y[i], v[i]);
addValue(r[3], t[i], x[i], y[i], v[i]);
}
addPeakResults(r[4], x, y, v);
addPeakResults(r[5], t, x, y, v);
addValues(r[6], x, y, v);
addValues(r[7], t, x, y, v);
float[][] image = new float[r.length][];
for (int i = 0; i < r.length; i++)
{
r[i].end();
image[i] = getImage(r[i]);
System.out.printf("[%d] = %s\n", i, Arrays.toString(image[i]));
}
// Test single value adds
float[] expecteds = image[0];
for (int i = 1; i < 4; i++)
{
float[] actuals = image[i];
Assert.assertArrayEquals("Image" + i, expecteds, actuals, 0);
}
// Test multi value adds
expecteds = image[4];
for (int i = 5; i < image.length; i++)
{
float[] actuals = image[i];
Assert.assertArrayEquals("Image" + i, expecteds, actuals, 0);
}
// Test they are roughly the same (differences occur due to floating point summation
Assert.assertArrayEquals("Single != Multi", expecteds, image[0], 1e-5f);
}
private static void begin(IJImagePeakResults r)
{
r.setDisplayImage(false);
r.begin();
}
private static void addPeakResult(IJImagePeakResults r, float x, float y, float v)
{
r.add(new PeakResult(x, y, 1, v));
}
private static void addPeakResult(IJImagePeakResults r, int t, float x, float y, float v)
{
r.add(new PeakResult(t, 0, 0, 0, 0, 0, createParams(x, y, v), null));
}
private static float[] createParams(float x, float y, float v)
{
float[] params = new float[7];
params[Gaussian2DFunction.X_POSITION] = x;
params[Gaussian2DFunction.Y_POSITION] = y;
params[Gaussian2DFunction.SIGNAL] = v;
return params;
}
private static void addPeakResults(IJImagePeakResults r, float[] x, float[] y, float[] v)
{
TurboList<PeakResult> results = new TurboList<PeakResult>(x.length);
for (int i = 0; i < x.length; i++)
results.add(new PeakResult(x[i], y[i], 1, v[i]));
r.addAll(results);
}
private static void addPeakResults(IJImagePeakResults r, int[] t, float[] x, float[] y, float[] v)
{
TurboList<PeakResult> results = new TurboList<PeakResult>(x.length);
for (int i = 0; i < x.length; i++)
results.add(new PeakResult(t[i], 0, 0, 0, 0, 0, createParams(x[i], y[i], v[i]), null));
r.addAll(results);
}
private static void addValue(IJImagePeakResults r, float x, float y, float v)
{
r.add(x, y, v);
}
private static void addValue(IJImagePeakResults r, int t, float x, float y, float v)
{
r.add(t, x, y, v);
}
private static void addValues(IJImagePeakResults r, float[] x, float[] y, float[] v)
{
r.add(x, y, v);
}
private static void addValues(IJImagePeakResults r, int[] t, float[] x, float[] y, float[] v)
{
r.add(t, x, y, v);
}
private static float[] getImage(IJImagePeakResults r)
{
return getImage(r.getImagePlus().getProcessor());
}
private static float[] getImage(ImageProcessor ip)
{
return (float[]) ip.convertToFloat().getPixels();
}
}