Java pixel matrix rotation
I tried to do an algorithm in java to rotate a 2d array (not limited to 90 degrees), the only problem I am having is the end result leaves me with dots / holes inside the image.
Here is the code:
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
int xp = (int) (nx + Math.cos(rotation) * (x - width / 2) + Math
.cos(rotation + Math.PI / 2) * (y - height / 2));
int yp = (int) (ny + Math.sin(rotation) * (x - width / 2) + Math
.sin(rotation + Math.PI / 2) * (y - height / 2));
int pixel = pixels[x + y * width];
Main.pixels[xp + yp * Main.WIDTH] = pixel;
}
}
"Main.pixels" is an array associated with the canvas display, this is what is displayed on the monitor.
'pixels', and the function itself, is in the sprite class. The sprite class grabs pixels from the ".png" image when the program is initialized.
I tried looking at the "Rotation Matrix" solutions. But they are too complicated for me. I noticed that when the image gets closer to the 45 degree point, the image is stretched a little? What's going wrong? And what is the correct code; which adds pixels to a larger scale array (eg Main.pixels []).
You need to be java! and regarding the format of the code above. I'm not looking for complicated examples, just because I don't understand (as stated above). Simple and straight to the point, this is what I'm looking for.
As an id as a question to be answered.
- Your formula is wrong because ....
- Do this and the effect will be ...
- Simplify this ...
- Id recommend ...
I'm sorry if I am asking for much, but I was looking for an answer regarding this question that I can understand and use. But always either set the rotation to 90 degrees, or an example from another programming language.
source to share
To avoid holes, you can:
-
calculate source coordinate from destination
(just change the computation to the current state) this is the same as Douglas Zare.
-
use bilinear or better filtering
-
use less than one pixel pitch
usually a
0.75
pixel is enough to cover the holes, but you have to usefloat
insteadint
, which is sometimes not possible (due to performance and / or lack of implementation or other reasons)
Distortion
if your image is distorted then you don't have the correct aspect ratio applied, so the x-pixel is different from the y-pixel. You need to add the scale to one axis to match the device / transforms being applied. Here are some tips:
-
Is the original image and the destination image separate (not in place)? therefore
Main.pixels
andpixels
are not the same ... otherwise you are overwriting some pixels before using them, which may be another cause of distortion. -
Just realize that you have
cos,cos
, andsin,sin
in the formula of rotation, which is not standard, and maybe you got the wrong signature triangle somewhere so
Just to be sure here for the bullet # 1 example . (reverse) with the standard rotation formula ( C ++ ):
float c=Math.cos(-rotation);
float s=Math.sin(-rotation);
int x0=Main.width/2;
int y0=Main.height/2;
int x1= width/2;
int y1= height/2;
for (int a=0,y=0; y < Main.height; y++)
for (int x=0; x < Main.width; x++,a++)
{
// coordinate inside dst image rotation center biased
int xp=x-x0;
int yp=y-y0;
// rotate inverse
int xx=int(float(float(xp)*c-float(yp)*s));
int yy=int(float(float(xp)*s+float(yp)*c));
// coordinate inside src image
xp=xx+x1;
yp=yy+y1;
if ((xp>=0)&&(xp<width)&&(yp>=0)&&(yp<height))
Main.pixels[a]=pixels[xp + yp*width]; // copy pixel
else Main.pixels[a]=0; // out of src range pixel is black
}
source to share
You push pixels forward and not every pixel ends up in a discrete rotation map. You can get rid of whitespace by calculating the source of each pixel.
Instead
for each pixel p in the source
pixel q = rotate(p, theta)
q.setColor(p.getColor())
try
for each pixel q in the image
pixel p = rotate(q, -theta)
q.setColor(p.getColor())
It will still have visual artifacts. You can improve this by interpolating instead of rounding the coordinates of the original pixel p to integer values.
Edit: The rotation formulas looked weird, but they look ok after using trigger identities like cos (r + pi / 2) = -sin (r) and sin (r + pi / 2) = cos (r). They should not cause stretching.
source to share