/*-
* Copyright 2017 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.dataset.function;
import static org.junit.Assert.assertNotNull;
import java.util.Arrays;
import java.util.List;
import org.eclipse.dawnsci.analysis.api.roi.IRectangularROI;
import org.eclipse.dawnsci.analysis.dataset.roi.RectangularROI;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DoubleDataset;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.Random;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class RegisterData1DTest {
private static final int MAX = 6;
private static final double X_DELTA = 2.4;
private static final int X_SIZE = 366;
private static final int START = 3; // start divider
private static final int MARGIN = 10; // margin for ROI
private static final double OBJECT_X = 42.3;
@BeforeClass
public static void setUp() {
Random.seed(123571L);
}
@Test
public void testRegisterSynthetic() {
testRegisterSynthetic(1.17, 0);
}
@Test
public void testRegisterSyntheticWithROI() {
testRegisterSyntheticWithROI(0.23, 0);
}
@Test
public void testRegisterSyntheticNoisy() {
testRegisterSynthetic(2.9, 0.05); // 10% noise
}
@Test
public void testRegisterSyntheticNoisyWithROI() {
testRegisterSyntheticWithROI(1.56, 0.05); // 10% noise
}
@Test
public void testRegisterSyntheticVeryNoisy() {
testRegisterSynthetic(4.22, 0.1); // 20% noise
}
@Test
public void testRegisterSyntheticVeryNoisyWithROI() {
testRegisterSyntheticWithROI(2.2, 0.1); // 20% noise
}
private void testRegisterSynthetic(double delta, double noise) {
testRegisterSynthetic(null, delta, noise);
}
private void testRegisterSyntheticWithROI(double delta, double noise) {
double[] start = new double[] {X_SIZE/START - OBJECT_X - MARGIN, 0};
double[] end = start.clone();
end[0] += 2*OBJECT_X + MAX*X_DELTA + MARGIN;
end[1] = 1; // to get around auto-adjustment of start and angle
RectangularROI roi = new RectangularROI(start, end);
System.err.println(roi);
testRegisterSynthetic(roi, delta, noise);
}
private void testRegisterSynthetic(IRectangularROI roi, double delta, double noise) {
double[] shifts = generateShifts(MAX);
System.err.println(Arrays.toString(shifts));
IDataset[] images = createTestData(shifts, X_SIZE, noise);
RegisterData1D reg = new RegisterData1D();
DoubleDataset filter = DatasetFactory.ones(DoubleDataset.class, 5);
filter.imultiply(1./ ((Number) filter.sum()).doubleValue());
reg.setFilter(filter);
reg.setRectangle(roi);
List<? extends IDataset> coords = reg.value(images);
assertNotNull(coords);
for (int i = 0; i < MAX; i++) {
double v = coords.get(2*i).getDouble();
System.err.println(i + " -> " + v + " cf " + shifts[i]);
}
for (int i = 0; i < MAX; i++) {
double v = coords.get(2*i).getDouble();
Assert.assertEquals(shifts[i], v, delta);
}
}
public double[] generateShifts(int number) {
double[] shifts = new double[number];
for (int n = 0; n < number; n++) {
shifts[n] = n*X_DELTA;
}
return shifts;
}
public IDataset[] createTestData(double[] shifts, int width, double noise) {
int number = shifts.length;
IDataset[] data = new IDataset[number];
for (int n = 0; n < number; n++) {
double start = width/START + shifts[n];
data[n] = createData(width, start, noise);
}
return data;
}
/**
* Create height field
* @param width
* @param start
* @return image
*/
public IDataset createData(int width, double start, double noise) {
DoubleDataset data = DatasetFactory.zeros(width);
for (int i = 0; i < width; i++) {
double y = i - start;
double z = getZ(y);
if (z != 0) {
data.setItem(z, i);
}
}
if (noise != 0) {
DoubleDataset ndata = Random.randn(width).imultiply(noise);
data.iadd(ndata);
}
return data;
}
/**
* Truncated triangle
* @param x
* @return z
*/
private double getZ(double x) {
final double zmax = 0.5;
double ax = Math.abs(x);
if (ax > OBJECT_X) {
return 0;
}
double z = 1 - ax/OBJECT_X;
if (z > zmax) {
z = zmax;
}
return z;
}
}