我正在尝试编写3剪切旋转算法described by Alan Paeth的Java实现。问题不在于计算值,而是将旋转点拟合到图像网格上。在本文中,通过以下计算给出的3次连续剪切进行旋转:
通过以下公式从给定角度(θ;弧度)计算α和β:
使用这些公式,点围绕坐标系的中心旋转。
要更正负值,我将相应轴的最小计算坐标添加到每个点,以使最小值始终为0.
到目前为止我的Java实现:
ShiftPoint[] val = new ShiftPoint[m*n];
double minX = 0,minY = 0, maxX = 0, maxY = 0;
double alpha = -1d* Math.tan(Math.toRadians(theta)/2d);
double beta = Math.sin(Math.toRadians(theta));
for(int a = 0; a < m; a++) {
for(int b = 0; b < n; b++) {
ShiftPoint temp = new ShiftPoint(a, b, values[a][b]);
double newX = b + alpha * a; //first shear
double newY = a + beta * newX; //second shear
newX += alpha * newY; //third shear
temp.setX(newX);
temp.setY(newY);
val[m * b + b] = temp;
}
}
注意: ShiftPoint是一个简单的自编类,用于保存矩阵内的特定坐标和值(在图像处理的情况下:像素的rgb值)。 这是计算的图形表示:
问题: 虽然计算值似乎是正确的,并且图形表示显示旋转实际上有效,但我不确定如何将计算值拟合到固定网格上的图像(或2d数组)没有扭曲它。另外,我还不完全理解Paeths论文中给出的实施(对于x轴剪切):
我认为skewi是计算值的整数部分而skewf是小数部分,但是宽度,高度,颜色和左边应该是什么?另外:为什么他在y值上加0.5,并且在第一次计算时不考虑x值?
注意:我知道Java提供了简单的旋转图像的方法,但我正在尝试实现这个特定的算法,只是为了它的乐趣。我也知道可以通过网络搜索找到的3-5个网站(例如#1和#2)并尝试解释该算法,但首先他们不使用java,其次他们大多数参考Paeth的示例实现,因此它们并不十分有用。
答案 0 :(得分:0)
这种图像旋转方法背后的基本原理是双重的:
第一步通常是更容易的步骤,并且将涉及x&amp;的简单线性组合。 y坐标。剪切变换(不严格旋转,因为它们不能保留每个像素的区域)只涉及类似x - >的变换。 x + alpha * y。
Paeth的论文(自1986年以来)中给出的算法似乎是一种精心优化的方法,用于进行剪切变换的第二(插值)步骤。我认为这可归结为沿x轴的分段线性插值,但是以不对输出图像中的每个像素进行多个阵列查找的形式编写。更清晰(效率稍低)的方法可能涉及像skewf * pixel(x-skewi-1,y)+(1-skewf)* pixel(x-skewi,y)。
这种特殊的算法显然非常适用于单轴偏斜。对于一般旋转,您可能需要在每个2x2像素的像素上更像bilinear interpolation,这些像素围绕与旋转图像中每个像素的中心对应的未旋转位置。 (计算这个中心像素值可能是Paeth代码中y + 0.5的原点。)
考虑到我们现在相对于1986年的计算能力,我怀疑如果你为这个双线性插值包含一个明确的公式,你的代码会更容易理解,即使它确实使用了比Paeth的方法更多的数组查找,除非你真的需要最大的表现。