从二维变换矩阵中提取旋转、缩放值

Posted

技术标签:

【中文标题】从二维变换矩阵中提取旋转、缩放值【英文标题】:extract rotation, scale values from 2d transformation matrix 【发布时间】:2011-05-20 15:52:22 【问题描述】:

如何从二维变换矩阵中提取旋转、缩放和平移值?我的意思是有一个二维变换

matrix = [1, 0, 0, 1, 0, 0]

matrix.rotate(45 / 180 * PI)
matrix.scale(3, 4)
matrix.translate(50, 100)
matrix.rotate(30 / 180 * PI)
matrix.scale(-2, 4)

现在我的矩阵有值 [a, b, c, d, tx, ty]

让我们忘记上面的过程,假设我们只有值 a、b、c、d、tx、ty

如何通过 a、b、c、d、tx、ty 找到总旋转和缩放值

对不起我的英语

感谢您的提前

编辑

我认为它应该是某个地方的答案......

我刚刚在 Flash Builder (AS3) 中尝试过这样的

   var m:Matrix = new Matrix;
   m.rotate(.25 * Math.PI);
   m.scale(4, 5);
   m.translate(100, 50);
   m.rotate(.33 * Math.PI);
   m.scale(-3, 2.5);

   var shape:Shape = new Shape;
   shape.transform.matrix = m;

   trace(shape.x, shape.y, shape.scaleX, shape.scaleY, shape.rotation);

输出是:

x = -23.6 
y = 278.8 
scaleX = 11.627334873920528 
scaleY = -13.54222263865791 
rotation = 65.56274134518259 (in degrees)

【问题讨论】:

这个问题最适合math.stackexchange.com - 你会得到更快的回复:-) 我刚刚在这里:math.stackexchange.com/questions/13150/… 谢谢 给我们一个例子 a,b,c,d,tx,ty 值,让我们看看是否有任何答案符合您的期望。 (a=4.810188218418486, b=10.58569820374103, c=13.4489075059838, d=-1.5870322791938274, tx=-23.601120674381982, ty=2728) 【参考方案1】:

并非所有 a,b,c,d,tx,ty 的值都会产生有效的旋转序列。我假设上述值是 2D 中 3x3 齐次旋转矩阵的一部分

    | a  b  tx |
A = | c  d  ty |
    | 0  0  1  |

将坐标[x, y, 1] 转换为:

[x', y', 1] = A * |x|
                  |y|
                  |z|
因此将翻译设置为[dx, dy]=[tx, ty] 比例为sx = sqrt(a² + c²)sy = sqrt(b² + d²) 旋转角度为t = atan(c/d)t = atan(-b/a),它们也应该相同。

否则您没有有效的旋转矩阵。


上面的变换扩展为:

x' = tx + sx (x Cos θ - y Sin θ)
y' = ty + sy (x Sin θ + y Cos θ)

当顺序是旋转,然后是缩放,然后是平移。

【讨论】:

每个方向的缩放操作可能不同...缩放是一个向量... 感谢您的旋转和平移。关于比例,我们得到了一个计算出的缩放单个值 (s=sqrt(b^2+d^2)) 是否可以找到 scaleX 和 scaleY 值? 请记住 sign(a)=sign(sx)sign(b)=sign(sy),因为 cos() 函数的性质。 约定改变了。就像使用左手系统或右手系统一样。或预乘与后乘转换。或表示行主要与列主要顺序中的元素。或者存储仿射变换的最后一行(3×3 平面)与不存储(2×3 平面)。而且肯定还会有更多。 @ja72 同意使用了不同的约定,但在答案中,您使用了大多数书籍中用于A 的列向量约定。但是,与行向量相乘意味着您正在乘以 3 x 3 * 1 x 3,这是无效的。我冒昧地通过将其设为列向量来修复它,我希望没问题。【参考方案2】:

我今天遇到了这个问题,并找到了使用矩阵变换点的最简单解决方案。这样,您可以先提取平移,然后再提取旋转和缩放。

这仅适用于 x 和 y 始终缩放相同(统一缩放)。

鉴于您的矩阵 m 已经经历了一系列变换,

var translate:Point;
var rotate:Number;
var scale:Number;

// extract translation
var p:Point = new Point();
translate = m.transformPoint(p);
m.translate( -translate.x, -translate.y);

// extract (uniform) scale
p.x = 1.0;
p.y = 0.0;
p = m.transformPoint(p);
scale = p.length;

// and rotation
rotate = Math.atan2(p.y, p.x);

你去!

【讨论】:

【参考方案3】:

这方面的术语是矩阵分解。这是一个包含 skew 的解决方案,如 Frédéric Wang 所述。

function decompose_2d_matrix(mat) 
  var a = mat[0];
  var b = mat[1];
  var c = mat[2];
  var d = mat[3];
  var e = mat[4];
  var f = mat[5];

  var delta = a * d - b * c;

  let result = 
    translation: [e, f],
    rotation: 0,
    scale: [0, 0],
    skew: [0, 0],
  ;

  // Apply the QR-like decomposition.
  if (a != 0 || b != 0) 
    var r = Math.sqrt(a * a + b * b);
    result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
    result.scale = [r, delta / r];
    result.skew = [Math.atan((a * c + b * d) / (r * r)), 0];
   else if (c != 0 || d != 0) 
    var s = Math.sqrt(c * c + d * d);
    result.rotation =
      Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
    result.scale = [delta / s, s];
    result.skew = [0, Math.atan((a * c + b * d) / (s * s))];
   else 
    // a = b = c = d = 0
  

  return result;

【讨论】:

【参考方案4】:

如果在缩放中你在 x 和 y 中缩放了相同的量,那么矩阵的行列式,即 ad-bc,它告诉你面积乘数也会告诉你比例的线性变化 - 它会是行列式的平方根。 atan( b/a ) 或更好的 atan2( b,a ) 会告诉您旋转的总角度。

但是,由于您的缩放比例不均匀,因此通常无法将您的一系列旋转和缩放比例压缩为单个旋转,然后在 x 和 y 中进行单个非均匀缩放。

【讨论】:

以上是关于从二维变换矩阵中提取旋转、缩放值的主要内容,如果未能解决你的问题,请参考以下文章

shader编程-二维空间中使用矩阵实现物体的旋转缩放平移变换(WebGL-Shader开发基础03)

shader编程-二维空间中使用矩阵实现物体的旋转缩放平移变换(WebGL-Shader开发基础03)

旋转矩阵

计算机图形学-图形学中的基本变换(缩放平移旋转剪切镜像)

变换矩阵

二维图形的矩阵变换——基本概念