从二维变换矩阵中提取旋转、缩放值
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)