package fr.unistra.pelican.algorithms.geometric;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.InvalidParameterException;
import fr.unistra.pelican.util.Tools;
/**
* This class performs a 2D rotation of variable angle with a given
* interpolation method
*
* The methods available are NOINTERPOLATION, BILINEARINTERPOLATION and BICUBICINTERPOLATION
*
* @author Jonathan Weber, Lefevre, Benjamin Perret (BICUBICINTERPOLATION)
*/
public class Rotation2D extends Algorithm {
/**
* The input image
*/
public Image inputImage;
/**
* The rotation angle (in degrees)
*/
public double angle;
/**
* The interpolation method
*/
public int interpolation;
/**
* The output image
*/
public Image outputImage;
/**
* Constant representing the NOINTERPOLATION method
*/
public static final int NOINTERPOLATION = 0;
/**
* Constant representing the BILINEARINTERPOLATION method
*/
public static final int BILINEARINTERPOLATION = 1;
/**
* Constant representing the BICUBICINTERPOLATION method
*/
public static final int BICUBICINTERPOLATION = 2;
/**
* Default constructor
*/
public Rotation2D() {
super.inputs = "inputImage,angle,interpolation";
super.outputs = "outputImage";
}
/**
* performs a 2D rotation of variable angle with a given interpolation
* method
*
* @param inputImage
* The input image
* @param angledegree
* The rotation angle (in degrees)
* @param interpolation
* The interpolation method
* @return The output image
*/
@SuppressWarnings("unchecked")
public static <T extends Image> T exec(T inputImage, double angledegree,
int interpolation) {
return (T) new Rotation2D().process(inputImage, angledegree,
interpolation);
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() {
double angleradian = Math.toRadians(angle);
double xinput = inputImage.getXDim();
double yinput = inputImage.getYDim();
double tcos = Math.cos(-angleradian);
double tsin = Math.sin(-angleradian);
double atcos = Math.cos(angleradian);
double atsin = Math.sin(angleradian);
double newX=xinput * Math.abs(tcos) + yinput*Math.abs(tsin);
double newY=xinput * Math.abs(tsin) + yinput*Math.abs(tcos);
int xoutput = (int) Math.ceil(xinput * Math.abs(tcos) + yinput
* Math.abs(tsin));
int youtput = (int) Math.ceil(xinput * Math.abs(tsin) + yinput
* Math.abs(tcos));
// ugly hack to avoid dimension increases due to numerical errors...
//if(newX-xoutput < 0.000001)
// xoutput--;
//if(newY-youtput < 0.000001)
// youtput--;
int xm = inputImage.getXDim() / 2;
int ym = inputImage.getYDim() / 2;
int xrap = (xoutput - inputImage.getXDim()) / 2;
int yrap = (youtput - inputImage.getYDim()) / 2;
outputImage = inputImage.newInstance(xoutput, youtput, inputImage
.getZDim(), inputImage.getTDim(), inputImage.getBDim());
outputImage.fill(0.);
for (int b = 0; b < outputImage.getBDim(); b++)
for (int t = 0; t < outputImage.getTDim(); t++)
for (int z = 0; z < outputImage.getZDim(); z++)
for (int y = -yrap; y < outputImage.getYDim() - yrap; y++)
for (int x = -xrap; x < outputImage.getXDim() - xrap; x++) {
switch (interpolation) {
case Rotation2D.NOINTERPOLATION:
int xout = (int) Math.round((x - xm) * atcos
+ (y - ym) * atsin + xm);
int yout = (int) Math.round(-(x - xm) * atsin
+ (y - ym) * atcos + ym);
if (xout >= 0 && xout < inputImage.getXDim()
&& yout >= 0
&& yout < inputImage.getYDim()) {
outputImage.setPixelXYZTBDouble(x + xrap, y
+ yrap, z, t, b, inputImage
.getPixelXYZTBDouble(xout, yout, z,
t, b));
}
break;
case Rotation2D.BILINEARINTERPOLATION:
double xoutd = ((x - xm) * atcos + (y - ym)
* atsin + xm);
double youtd = (-(x - xm) * atsin + (y - ym)
* atcos + ym);
if (xoutd >= 0
&& xoutd < inputImage.getXDim() - 1
&& youtd >= 0
&& youtd < inputImage.getYDim() - 1) {
int xout_floor = (int) Math.floor(xoutd);
int yout_floor = (int) Math.floor(youtd);
int xout_ceil = (int) Math.ceil(xoutd);
int yout_ceil = (int) Math.ceil(youtd);
double interpolation = 0;
interpolation += inputImage
.getPixelXYZTBDouble(xout_floor,
yout_floor, z, t, b);
interpolation += inputImage
.getPixelXYZTBDouble(xout_floor,
yout_ceil, z, t, b);
interpolation += inputImage
.getPixelXYZTBDouble(xout_ceil,
yout_floor, z, t, b);
interpolation += inputImage
.getPixelXYZTBDouble(xout_ceil,
yout_ceil, z, t, b);
interpolation = interpolation / 4;
outputImage.setPixelXYZTBDouble(x + xrap, y
+ yrap, z, t, b, interpolation);
}
break;
case Rotation2D.BICUBICINTERPOLATION:
xoutd = ((x - xm) * atcos + (y - ym)
* atsin + xm);
youtd = (-(x - xm) * atsin + (y - ym)
* atcos + ym);
if (xoutd >= 0
&& xoutd < inputImage.getXDim() - 1
&& youtd >= 0
&& youtd < inputImage.getYDim() - 1) {
double interpolation = Tools.getBiCubicInterpolation(inputImage, xoutd, youtd, z, t, b);
outputImage.setPixelXYZTBDouble(x + xrap, y
+ yrap, z, t, b, interpolation);
}
break;
default:
throw new InvalidParameterException(
"Bad Argument for interpolation");
}
}
}
}