【问题标题】:Arbitrary angle rotation through shear (Paeth algorithm)通过剪切任意角度旋转(Paeth 算法)
【发布时间】:2018-05-17 02:40:01
【问题描述】:

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

  1. x = x + alpha * y
  2. y= y + beta * x
  3. x = x + alpha * y

Alpha 和 beta 是通过以下公式从给定角度(theta;in radians)计算出来的:

  • 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 值)。 这是计算的图形表示:

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

我知道 skewi 是计算值的整数部分,而 skewf 是小数部分,但宽度、高度、oleft 和 left 应该是什么?另外:为什么他在第一次计算时将 y 值加 0.5 而没有考虑 x 值?

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

【问题讨论】:

    标签: java algorithm image-processing rotation


    【解决方案1】:

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

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

    第一步通常比较容易,涉及到 x 和 y 坐标的简单线性组合。剪切变换(不是严格的旋转,因为它们不保留每个像素的面积)只涉及 x -> x + alpha * y 之类的东西。

    Paeth 的论文(可追溯到 1986 年)中给出的算法似乎是一种经过精心优化的方法,用于执行剪切变换的第二步(插值)。我认为这归结为沿 x 轴的分段线性插值,但以一种不需要对输出图像中的每个像素进行多个数组查找的形式编写。更清晰(但效率稍低)的方法可能涉及类似 skewf * pixel(x-skewi-1, y) + (1-skewf) * pixel(x-skewi, y) 的方法。

    这种特殊的算法显然是高度专门用于单轴倾斜的。对于一般旋转,您可能需要更类似于bilinear interpolation 在每个 2x2 正方形像素上,这些像素围绕未旋转位置对应于旋转图像中每个像素的中心。 (计算这个中心像素值可能是 Paeth 代码中 y+0.5 的原点。)

    鉴于我们现在相对于 1986 年拥有多少计算能力,我怀疑如果您为此双线性插值包含一个明确的公式,您的代码会更容易理解,即使它确实使用比 Paeth 的方法更多的数组查找,除非您真的需要最高性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-13
      相关资源
      最近更新 更多