package uk.ac.diamond.scisoft.analysis.processing.operations.image;
import org.eclipse.dawnsci.analysis.api.image.IImageTransform;
import org.eclipse.dawnsci.analysis.api.processing.OperationData;
import org.eclipse.dawnsci.analysis.api.processing.OperationException;
import org.eclipse.dawnsci.analysis.api.processing.OperationRank;
import org.eclipse.january.DatasetException;
import org.eclipse.january.IMonitor;
import org.eclipse.january.MetadataException;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.DatasetFactory;
import org.eclipse.january.dataset.DatasetUtils;
import org.eclipse.january.dataset.IDataset;
import org.eclipse.january.dataset.ILazyDataset;
import org.eclipse.january.metadata.AxesMetadata;
import org.eclipse.january.metadata.MetadataFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.diamond.scisoft.analysis.processing.operations.utils.OperationServiceLoader;
public class AffineTransformImageOperation extends AbstractSimpleImageOperation<AffineTransformImageModel> {
private final Logger logger = LoggerFactory.getLogger(AffineTransformImageOperation.class);
@Override
public String getId() {
return "uk.ac.diamond.scisoft.analysis.processing.operations.AffineTransformImageOperation";
}
@Override
protected OperationData process(IDataset input, IMonitor monitor) throws OperationException {
if (imageFilterService == null)
imageFilterService = OperationServiceLoader.getImageFilterService();
if (imageTransformService == null)
imageTransformService = OperationServiceLoader.getImageTransformService();
IDataset out = processImage(input, monitor);
//check if dimensions of the data changed after processing
if (input.getShape()[0] == out.getShape()[0] && input.getShape()[1] == out.getShape()[1]) {
copyMetadata(input, out);
} else {
copyMetadata(input, out, false);
ILazyDataset[] axes = getFirstAxes(input);
if (axes != null) {
Dataset axis_new_x = null;
Dataset axis_new_y = null;
if (axes[0] != null) {
Dataset axis_old_x = null;
try {
axis_old_x = DatasetUtils.sliceAndConvertLazyDataset(axes[0]);
} catch (DatasetException e) {
throw new OperationException(this, e);
}
//check if axes is 1 or 2 dimensional
if (axis_old_x.getRank() == 1) {
//1D
axis_new_x = DatasetFactory.zeros(new int[]{out.getShape()[0]}, axis_old_x.getDType());
for (int i = 0 ; i < out.getShape()[0] ; i++) {
double new_value = axis_old_x.getDouble(0) + (axis_old_x.getDouble(axis_old_x.getShape()[0]-1) - axis_old_x.getDouble(0)) * i / (out.getShape()[0]-1);
axis_new_x.set(new_value, i);
}
} else {
//2D
axis_new_x = DatasetFactory.zeros(out.getShape(), axis_old_x.getDType());
for (int i = 0 ; i < out.getShape()[0] ; i++) {
double new_value = axis_old_x.getDouble(0, 0) + (axis_old_x.getDouble(axis_old_x.getShape()[0]-1, 0) - axis_old_x.getDouble(0, 0)) * i / (out.getShape()[0]-1);
for (int j = 0 ; j < out.getShape()[1] ; j++) {
//System.out.println("i: " + i + " j: " + j);
axis_new_x.set(new_value, i, j);
}
}
}
axis_new_x.setName(axis_old_x.getName());
}
if (axes[1] != null) {
Dataset axis_old_y = null;
try {
axis_old_y = DatasetUtils.sliceAndConvertLazyDataset(axes[1]);
} catch (DatasetException e) {
throw new OperationException(this, e);
}
//check if axes is 1 or 2 dimensional
if (axis_old_y.getRank() == 1) {
//1D
axis_new_y = DatasetFactory.zeros(new int[]{out.getShape()[1]}, axis_old_y.getDType());
for (int j = 0 ; j < out.getShape()[1] ; j++) {
double new_value = axis_old_y.getDouble(0) + (axis_old_y.getDouble(axis_old_y.getShape()[0]-1) - axis_old_y.getDouble(0)) * j / (out.getShape()[1]-1);
axis_new_y.set(new_value, j);
}
} else {
//2D
axis_new_y = DatasetFactory.zeros(out.getShape(), axis_old_y.getDType());
for (int j = 0 ; j < out.getShape()[1] ; j++) {
double new_value = axis_old_y.getDouble(0, 0) + (axis_old_y.getDouble(0, axis_old_y.getShape()[1]-1) - axis_old_y.getDouble(0, 0)) * j / (out.getShape()[1]-1);
for (int i = 0 ; i < out.getShape()[0] ; i++) {
axis_new_y.set(new_value, i, j);
}
}
}
axis_new_y.setName(axis_old_y.getName());
}
AxesMetadata amd = null;
try {
amd = MetadataFactory.createMetadata(AxesMetadata.class, 2);
} catch (MetadataException e) {
throw new OperationException(this, e);
}
amd.setAxis(0, axis_new_x);
amd.setAxis(1, axis_new_y);
out.addMetadata(amd);
}
}
return new OperationData(out);
}
@Override
public IDataset processImage(IDataset dataset, IMonitor monitor) {
IImageTransform service = getImageTransformService();
double a11 = ((AffineTransformImageModel)model).getA11();
double a12 = ((AffineTransformImageModel)model).getA12();
double a21 = ((AffineTransformImageModel)model).getA21();
double a22 = ((AffineTransformImageModel)model).getA22();
double dx = ((AffineTransformImageModel)model).getDx();
double dy = ((AffineTransformImageModel)model).getDy();
boolean resize = ((AffineTransformImageModel)model).isResize();
IDataset transformed = null;
try {
transformed = service.affineTransform(dataset, a11, a12, a21, a22, dx, dy, !resize);
} catch (Exception e) {
logger.error("An error occured while performing the affine transformation:", e);
}
return transformed;
}
@Override
public OperationRank getInputRank() {
return OperationRank.TWO;
}
@Override
public OperationRank getOutputRank() {
return OperationRank.TWO;
}
}