从仿射变换矩阵得到偏斜或旋转值

时间:2012-09-18 02:53:32

标签: actionscript-3 flash math

我正试图从闪存影片剪辑中的转换矩阵中获取偏斜值。转换矩阵由

表示
a b tx
c d ty
0 0 1

我没有关于执行什么类型的转换以及哪个转换的信息。我知道在flash中你只能旋转或歪曲一个影片剪辑(如果我错了,请纠正我)。我可以从影片剪辑的scaleX和scaleY属性中获取缩放值。我认为翻译并不重要,我可以将tx和ty等同为零。

所以我的问题有2个部分。如何确定是否应用了倾斜或旋转,以及如何获取相应的值?

4 个答案:

答案 0 :(得分:2)

2D旋转矩阵

cos(theta) -sin(theta)
sin(theta)  cos(theta)

所以如果你没有应用缩放或剪切,

   a = d
and
   c = -b
and the angle of rotation is
   theta = asin(c) = acos(a)

如果你已经应用了缩放并且可以恢复缩放因子sx和sy,只需将第一行除以sx,将第二行除以原始变换矩阵中的sy,然后如上所述恢复旋转角度。

如果你在那里的任何地方都有剪切(歪斜),我和之前的评论者一样,除非在非常有限的情况下(例如一次只有一个已知方向的剪切)一个已知的命令)。

答案 1 :(得分:2)

你需要进行极性分解。这篇维基百科文章解释了它的工作原理: http://en.wikipedia.org/wiki/Polar_decomposition 这是我使用OpenCV库为自己的程序编写的代码。



const double PI = 3.141592653;
    cv::Mat rotationOutput = cv::Mat::zeros(warp00.size(),CV_64F);
    cv::Mat_<double>::iterator rotIter = rotationOutput.begin<double>();
    cv::Mat_<double>::iterator warp00Iter = warp00.begin<double>();
    cv::Mat_<double>::iterator warp01Iter = warp01.begin<double>();
    cv::Mat_<double>::iterator warp10Iter = warp10.begin<double>();
    cv::Mat_<double>::iterator warp11Iter = warp11.begin<double>();

    for(; warp00Iter != warp00.end<double>(); ++warp00Iter, ++warp01Iter, ++warp10Iter,
        ++warp11Iter, ++rotIter){
        cv::Matx22d fMatrix(*warp00Iter,*warp01Iter, *warp10Iter, *warp11Iter);
        cv::Matx22d cMatrix;
        cv::Matx22d cMatSqrt(0.,0.,0.,0.);
        cv::mulTransposed(fMatrix, cMatrix, true);
        cv::Matx21d eigenVals;
        cv::Matx22d eigenVecs;
        if((cMatrix(0,0) !=0.) && (cMatrix(1,1) !=0.)){
            if(cv::eigen(cMatrix,true,eigenVals,eigenVecs)){
                cMatSqrt = eigenVecs.t()*
                        cv::Matx22d(sqrt(eigenVals(0,0)),0.,0.,sqrt(eigenVals(1,0)))*eigenVecs;
            }
        }
        cv::Matx22d rMat = fMatrix*cMatSqrt.inv();
        *rotIter = atan(rMat(1,0)/rMat(0,0));
        
    }
&#13;
&#13;
&#13;

warp00,warp01,warp10和warp11包含仿射变换的前4个参数(不需要转换参数warp02和warp12)。在你的情况下,它将是a,b,c,d。 您将在维基百科文章中注意到您需要计算矩阵的平方根。唯一的方法是计算特征值,然后计算它们的平方根并将对角矩阵旋转回原始坐标系。 它很复杂,但是当你进行仿射变换时,它是计算旋转的唯一方法。 在我的情况下,我只关心旋转,所以我的代码不会给你歪斜。

答案 2 :(得分:0)

首先,您可以同时进行倾斜和旋转,但必须先选择顺序。解释了偏斜矩阵here,为您创建新矩阵的变换添加偏斜矩阵并执行yourTransformMatrix.concat(skewMatrix);

目前我无法说明您是否可以根据&#34;旋转角度&#34;,&#34; skew_X angle&#34;,&#34; skew_Y angle&#34;来检索转换值。 ,&#34; translation_X&#34;,&#34; translation_Y&#34;,这通常是一个非线性方程系统,可能没有特定矩阵的解。

答案 3 :(得分:0)

此术语是矩阵分解。这是一种解决方案,其中包括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;
}