通过剪切的任意角度旋转(Paeth算法)

时间:2017-12-03 15:04:41

标签: java algorithm image-processing rotation

我正在尝试编写3剪切旋转算法described by Alan Paeth的Java实现。问题不在于计算值,而是将旋转点拟合到图像网格上。在本文中,通过以下计算给出的3次连续剪切进行旋转:

  1. x = x + alpha * y
  2. y = y + beta * x
  3. x = x + alpha * y
  4. 通过以下公式从给定角度(θ;弧度)计算α和β:

    • beta = sin(theta)
    • alpha = - tan(theta / 2)

    使用这些公式,点围绕坐标系的中心旋转。

    要更正负值,我将相应轴的最小计算坐标添加到每个点,以使最小值始终为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值)。 这是计算的图形表示: enter image description here

    问题: 虽然计算值似乎是正确的,并且图形表示显示旋转实际上有效,但我不确定如何将计算值拟合到固定网格上的图像(或2d数组)没有扭曲它。另外,我还不完全理解Paeths论文中给出的实施(对于x轴剪切):

    enter image description here

    我认为skewi是计算值的整数部分而skewf是小数部分,但是宽度,高度,颜色和左边应该是什么?另外:为什么他在y值上加0.5,并且在第一次计算时不考虑x值?

    注意:我知道Java提供了简单的旋转图像的方法,但我正在尝试实现这个特定的算法,只是为了它的乐趣。我也知道可以通过网络搜索找到的3-5个网站(例如#1#2)并尝试解释该算法,但首先他们不使用java,其次他们大多数参考Paeth的示例实现,因此它们并不十分有用。

1 个答案:

答案 0 :(得分:0)

这种图像旋转方法背后的基本原理是双重的:

  • 定义旋转x&amp;的坐标变换。旋转图像中的y轴到x&amp;原始图像的y轴
  • 通过在原始图像中对应点附近的值之间进行插值来计算旋转图像中的每个像素

第一步通常是更容易的步骤,并且将涉及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的方法更多的数组查找,除非你真的需要最大的表现。