4

I'm trying to get the skew values out of a transformation matrix in a flash movie clip. The transformation matrix is represented by

a b tx
c d ty
0 0 1

I have no information on what kind of transformation is performed and which comes first. I do know that in flash, you may only rotate OR skew a movie clip (correct me if I am wrong). I can get scale values from scaleX and scaleY properties of the movie clip. I believe translation does not quite matter i can just equate tx and ty to zero.

so my question has 2 parts. How do I determine if a skew or a rotation had been applied, and how do I get the respective values?

4

4 回答 4

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));
        
    }

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

于 2014-12-23T05:03:07.597 回答
2

二维旋转矩阵是

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,然后如上所述恢复旋转角度。

如果您在那里的任何地方都应用了剪切(倾斜),我和以前的评论者在一起,除非在非常有限的情况下(例如一次仅在一个已知方向上以已知顺序剪切),否则可能是不可能的)。

于 2012-09-21T23:24:47.627 回答
2

The term for this is matrix decomposition. Here is a solution that includes skew as described by Frédéric Wang.

Works when transforms are applied in this order: skew, scale, rotate, translate.

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;
}
于 2018-08-19T20:09:10.490 回答
0

首先,您可以同时进行倾斜和旋转,但您必须先选择顺序。这里解释了一个倾斜矩阵,要将一个倾斜矩阵添加到一个转换中,您可以创建一个新矩阵并执行yourTransformMatrix.concat(skewMatrix);

我目前不能说您是否可以根据“旋转角度”、“skew_X 角度”、“skew_Y 角度”、“translation_X”、“translation_Y”检索变换值,这通常是一个非线性方程组,可能不会有一个特定矩阵的解决方案。

于 2012-09-18T07:11:35.480 回答