/*-
* Copyright 2016 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.image;
import java.util.List;
import org.apache.commons.math3.special.Erf;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.IndexIterator;
import org.junit.Assert;
import org.junit.Test;
public class ImageUtilsTest {
private static final double mobrt = -Math.sqrt(0.5);
/**
* Returns CDF of unit Gaussian centred on zero
* @param x
* @return CDF
*/
private static double cdfGaussian(double x) {
return 0.5*Erf.erfc(mobrt*x);
}
private void distributePeak(Dataset data, double[] centre, double width, double amplitude) {
int rank = data.getRank();
int[] start = new int[rank];
int[] stop = new int[rank];
int window = (int) Math.ceil(6*width); // 3 sigma
for (int i = 0; i < rank; i++) {
start[i] = (int) (Math.floor(centre[i]) - window/2);
stop[i] = start[i] + window;
}
double f = 1./width;
IndexIterator it = data.getSliceIterator(start, stop, null);
int[] pos = it.getPos();
while (it.hasNext()) {
double v = 1;
for (int j = 0; j < rank; j++) {
double x = f * (pos[j] - centre[j]);
v *= cdfGaussian(x + f) - cdfGaussian(x);
}
data.setObjectAbs(it.index, v*amplitude + data.getElementDoubleAbs(it.index));
}
}
private static final double REL_TOL = 1e-2;
@Test
public void testDistributePeak() {
final int size = 128;
final double amp = 5;
// 1D
double[] centre = new double[] {32.3};
Dataset data = DatasetFactory.zeros(new int[] {size}, Dataset.FLOAT64);
distributePeak(data, centre, 5, amp);
double sum = ((Number) data.sum()).doubleValue();
Assert.assertEquals(amp, sum, REL_TOL*amp);
data.fill(0);
distributePeak(data, centre, 0.5, amp);
sum = ((Number) data.sum()).doubleValue();
Assert.assertEquals(amp, sum, REL_TOL*amp);
// 2D
centre = new double[] {32.3, 72.7};
data = DatasetFactory.zeros(new int[] {size, size}, Dataset.FLOAT64);
distributePeak(data, centre, 5, amp);
sum = ((Number) data.sum()).doubleValue();
Assert.assertEquals(amp, sum, REL_TOL*amp);
data.fill(0);
distributePeak(data, centre, 0.5, amp);
sum = ((Number) data.sum()).doubleValue();
Assert.assertEquals(amp, sum, REL_TOL*amp);
}
@Test
public void testSinglePeak1D() {
final int size = 32;
final int window = 3;
final double amp = 5;
double[] centre = new double[] {12.3};
Dataset data = DatasetFactory.zeros(new int[] {size}, Dataset.FLOAT64);
distributePeak(data, centre, 0.5, amp);
List<Dataset> result = ImageUtils.findWindowedPeaks(data, window, 0.1*amp, 1.1*amp);
Assert.assertEquals(2, result.size());
Dataset sum = result.get(0);
Assert.assertEquals(1, sum.getSize());
Assert.assertArrayEquals(new int[] {1}, sum.getShapeRef());
Assert.assertEquals(amp, sum.getDouble(0), REL_TOL*amp);
Dataset coords = result.get(1);
Assert.assertArrayEquals(new int[] {1, 1}, coords.getShapeRef());
Assert.assertEquals(centre[0], coords.getDouble(0, 0), REL_TOL*centre[0]);
}
@Test
public void testSinglePeak2D() {
final int size = 128;
final int window = 3;
final double amp = 5;
double[] centre = new double[] {32.3, 72.7};
Dataset data = DatasetFactory.zeros(new int[] {size, size}, Dataset.FLOAT64);
distributePeak(data, centre, 0.5, amp);
List<Dataset> result = ImageUtils.findWindowedPeaks(data, window, 0.1*amp, 1.1*amp);
Assert.assertEquals(2, result.size());
Dataset sum = result.get(0);
Assert.assertEquals(1, sum.getSize());
Assert.assertArrayEquals(new int[] {1}, sum.getShapeRef());
Assert.assertEquals(amp, sum.getDouble(0), REL_TOL*amp);
Dataset coords = result.get(1);
Assert.assertArrayEquals(new int[] {1, 2}, coords.getShapeRef());
Assert.assertEquals(centre[0], coords.getDouble(0, 0), REL_TOL*centre[0]);
Assert.assertEquals(centre[1], coords.getDouble(0, 1), REL_TOL*centre[1]);
}
}