PDA

View Full Version : [Java] Rotating images 90 degrees or multiples thereof




wrldwzrd89
Nov 14, 2010, 12:58 PM
Here's my rotation code, as it stands now:

private static BufferedImage rotateImage(BufferedImage inputImage,
double[] transformData) {
BufferedImage outputImage = new BufferedImage(inputImage.getWidth(),
inputImage.getHeight(), inputImage.getType());
int degrees = (int) transformData[0];
int xPrime, yPrime;
int xTrans = (int) (inputImage.getWidth() * Math.sin(degrees));
int yTrans = (int) (inputImage.getHeight() * Math.cos(degrees));
for (int x = 0; x < inputImage.getWidth(); x++) {
for (int y = 0; y < inputImage.getHeight(); y++) {
xPrime = (int) (x * Math.cos(degrees) - y * Math.sin(degrees) + xTrans);
yPrime = (int) (x * Math.sin(degrees) + y * Math.cos(degrees) + yTrans);
outputImage.setRGB(xPrime, yPrime, inputImage.getRGB(x, y));
}
}
return outputImage;
}

The transformData array contains the degrees to rotate as the first (and only) element. However, this is not working - the problem appears to be one of coordinates being out of bounds for the image after rotation. Obviously they need to be adjusted after the formula is applied (which I found on Wikipedia - here (http://en.wikipedia.org/wiki/Rotation_%28mathematics%29)). I cannot figure out the right offset.



winninganthem
Nov 14, 2010, 03:13 PM
What are xTrans and yTrans for?

I would have print statements in your inner for loop to print every single xPrime, yPrime pair. This might help you so that you'll know what kind of computations are going on.

Another note that might be relevant: Dealing with integer types is one of the reasons why implementing computational geometry is difficult. For example, you cast your xPrime and yPrime coordinates down to ints and might lose some data. There are some devious ways to perform these calculations perfectly without using doubles, but I can't quite remember at the moment.

chown33
Nov 14, 2010, 03:47 PM
At least use AffineTransform. Coding it yourself pixel-by-pixel is silly. And your trig is wrong: the Math trig functions operate in radians, not degrees.

At best, don't use AffineTransform or any trig functions at all. When the angles are all multiples of 90 degrees, you don't need an AffineTransform. Simply transpose X & Y (i.e. use Y for X, and X for Y) as appropriate. That is, rows become columns, and columns become rows. This will be clearer if you know the sin and cos of 90, 180, and 270 degrees.

Some other trivial arithmetic may also be needed, but it shouldn't be hard to figure this out by a simple analysis of the problem and its solutions for 90, 180, and 270 degrees. You can do the analysis on a tiny image, say 4 pixels by 5 pixels. The principles are identical regardless of dimensions.


BufferedImage outputImage = new BufferedImage(inputImage.getWidth(),
inputImage.getHeight(), inputImage.getType());

This won't work in half the cases, unless inputImage is square. The BufferedImage's dimensions need to be calculated from the ROTATED dimensions of inputImage. Otherwise the output image will be clipped, or pixel coords will be out of bounds. Again, do the basic analysis on a tiny image, 4x5 pixels, and see what happens. By "basic analysis" I mean carry out the calculation by hand.

wrldwzrd89
Nov 14, 2010, 04:22 PM
Thanks, guys. That helps a lot more than you might think.

SidBala
Nov 14, 2010, 05:26 PM
In any image transformation algorithms, I would always recommend backwards mapping.

Instead of going over each pixel in your input image and then moving them over to the final image, go over each pixel in the final image and figure out the corresponding pixel in the input.

In your simple 90 degree algorithm, it will make no difference. But if you do more complex things, like non-90 degree rotations, or if you do scaling etc, you will end up with "holes" in your output image.

Either way, you will need to do bounds checking.


EDIT: Also precalculate your rotation matrix outside the loop. This will make the calculations super fast too.