Java 像素阵列旋转
Java rotation of pixel array
我试图在 java 中制作一个算法来旋转二维像素阵列(不限于 90 度),我遇到的唯一问题是:最终结果让我 dots/holes在图像中。
这是代码:
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' 是连接到 canvas 显示器的数组,这就是显示器上显示的内容。
'pixels' 和函数本身在精灵 class 中。精灵 class 在程序初始化时从 '.png' 图像中抓取像素。
我试过查看 'Rotation Matrix' 解决方案。但它们对我来说太复杂了。我注意到当图像接近 45 度时,图像会有些拉伸?出了什么问题?什么是正确的代码;将像素添加到更大比例的数组(例如 Main.pixels[])。
需要java!并且相对于上面的代码格式。我不是在寻找复杂的例子,只是因为我不明白(如上所述)。简单明了,正是我要找的。
我喜欢这个问题的答案。
- 你的公式是错误的,因为....
- 这样做,效果会是...
- 简化这个...
- 我推荐...
对不起,如果我问的太多了,但我已经在寻找与这个问题相关的答案,我可以理解和使用。但是总是要么给出 90 度的旋转,要么给出来自另一种编程语言的示例。
您正在推动像素向前,并不是每个像素都被离散化旋转贴图击中。您可以通过计算每个像素的来源来消除间隙。
而不是
for each pixel p in the source
pixel q = rotate(p, theta)
q.setColor(p.getColor())
尝试
for each pixel q in the image
pixel p = rotate(q, -theta)
q.setColor(p.getColor())
这仍然会有视觉瑕疵。您可以通过插值而不是将源像素 p 的坐标四舍五入为整数值来改进这一点。
编辑:您的旋转公式看起来很奇怪,但在使用像 cos(r+pi/2) = -sin(r) 和 sin(r+pi/2)=cos( r)。它们不应该是任何拉伸的原因。
要避免漏洞,您可以:
从目标计算源坐标
(只需将计算反转为您当前的状态)它与 Douglas Zare 的答案相同
使用双线性或更好的过滤
使用更少的单像素步长
通常 0.75
像素足以覆盖孔,但您需要使用 float
s 而不是 int
s,这有时是不可能的(由于性能和/或缺少实现或其他原因)
失真
如果您的图像变形,那么您没有正确应用纵横比,因此 x 像素大小与 y 像素大小不同。您需要向一个轴添加刻度,使其与应用的 device/transforms 相匹配。这里有一些提示:
源图和目的图是否分离(不在位)?所以 Main.pixels
和 pixels
不是一回事......否则你会在使用之前覆盖一些像素,这可能是造成失真的另一个原因。
刚意识到你在旋转公式中有 cos,cos
和 sin,sin
,这是非标准的,可能是你在某处错误地签署了角度增量所以
这里只是为了确定子弹的例子 #1。 (反向)使用标准旋转公式 (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
}
我试图在 java 中制作一个算法来旋转二维像素阵列(不限于 90 度),我遇到的唯一问题是:最终结果让我 dots/holes在图像中。
这是代码:
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' 是连接到 canvas 显示器的数组,这就是显示器上显示的内容。
'pixels' 和函数本身在精灵 class 中。精灵 class 在程序初始化时从 '.png' 图像中抓取像素。
我试过查看 'Rotation Matrix' 解决方案。但它们对我来说太复杂了。我注意到当图像接近 45 度时,图像会有些拉伸?出了什么问题?什么是正确的代码;将像素添加到更大比例的数组(例如 Main.pixels[])。
需要java!并且相对于上面的代码格式。我不是在寻找复杂的例子,只是因为我不明白(如上所述)。简单明了,正是我要找的。
我喜欢这个问题的答案。
- 你的公式是错误的,因为....
- 这样做,效果会是...
- 简化这个...
- 我推荐...
对不起,如果我问的太多了,但我已经在寻找与这个问题相关的答案,我可以理解和使用。但是总是要么给出 90 度的旋转,要么给出来自另一种编程语言的示例。
您正在推动像素向前,并不是每个像素都被离散化旋转贴图击中。您可以通过计算每个像素的来源来消除间隙。
而不是
for each pixel p in the source
pixel q = rotate(p, theta)
q.setColor(p.getColor())
尝试
for each pixel q in the image
pixel p = rotate(q, -theta)
q.setColor(p.getColor())
这仍然会有视觉瑕疵。您可以通过插值而不是将源像素 p 的坐标四舍五入为整数值来改进这一点。
编辑:您的旋转公式看起来很奇怪,但在使用像 cos(r+pi/2) = -sin(r) 和 sin(r+pi/2)=cos( r)。它们不应该是任何拉伸的原因。
要避免漏洞,您可以:
从目标计算源坐标
(只需将计算反转为您当前的状态)它与 Douglas Zare 的答案相同
使用双线性或更好的过滤
使用更少的单像素步长
通常
0.75
像素足以覆盖孔,但您需要使用float
s 而不是int
s,这有时是不可能的(由于性能和/或缺少实现或其他原因)
失真
如果您的图像变形,那么您没有正确应用纵横比,因此 x 像素大小与 y 像素大小不同。您需要向一个轴添加刻度,使其与应用的 device/transforms 相匹配。这里有一些提示:
源图和目的图是否分离(不在位)?所以
Main.pixels
和pixels
不是一回事......否则你会在使用之前覆盖一些像素,这可能是造成失真的另一个原因。刚意识到你在旋转公式中有
cos,cos
和sin,sin
,这是非标准的,可能是你在某处错误地签署了角度增量所以
这里只是为了确定子弹的例子 #1。 (反向)使用标准旋转公式 (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
}