2014-10-17 1 views
0

Я нашел несколько сообщений об этой теме, но ни одно из решений не использует opencv.Как найти угол поворота и перевод с помощью opencv, если я знаю однородную матрицу преобразования в 3d?

Мне интересно, имеет ли OpenCv какую-либо функцию или класс, который мог бы помочь в этом вопросе?

У меня есть аффинное преобразование 4 * 4 в opencv, и я ищу, чтобы найти поворот, перевод, предполагающий, что масштабирование равно 1, и в матрице нет другого преобразования.

Есть ли какая-либо функция в OpenCV, чтобы помочь найти эти параметры?

+0

[Родригес] (http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#rodrigues)? – berak

+0

@berak: Спасибо. Вы предлагаете получить матрицу вращения 3X3 и использовать указанную выше функцию для получения углов и поиска перевода с использованием матрицы 4X4? – mans

+0

есть. если вы отрубите последнюю строку-vec из 4x4, это ваш перевод. если вы отрубите последний col-vec из оставшихся 3x4, вы получите мат 3x3. предполагая, что вам нужны углы (я не уверен), подайте это в Родригес. (или сохранить его как есть, если вы хотите Mat) – berak

ответ

0

Проблема, с которой вы сталкиваетесь, называется проблемой разложения матрицы.

Вы можете получить желаемые матрицы, выполнив следующие действия:

  1. вычислим коэффициенты масштабирования в качестве величин первых трех базисных векторов (столбцов или строк) матрицы
  2. Разделить первые три базисные векторы по этим значениям (таким образом, нормализуя их)
  3. Верхняя левая часть матрицы 3x3 теперь представляет собой поворот (вы можете использовать это как есть или преобразовать его в форму кватерниона)
  4. Перевод является четвертым базовым вектором матрица (в гомогенных ous координат - это будут первые три элемента, которые вас интересуют)

В вашем случае, являясь вашим коэффициентом масштабирования 1, вы можете пропустить первые два шага.
Чтобы получить ось и угол матрицы вращения (в радианах), я предлагаю вам перенести следующий алгоритм Java в OpenCV (источник: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/).

/** 
This requires a pure rotation matrix 'm' as input. 
*/ 
public axisAngle toAxisAngle(matrix m) { 
    double angle,x,y,z; // variables for result 
    double epsilon = 0.01; // margin to allow for rounding errors 
    double epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees 
    // optional check that input is pure rotation, 'isRotationMatrix' is defined at: 
    // http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/ 
    assert isRotationMatrix(m) : "not valid rotation matrix" ;// for debugging 
    if ((Math.abs(m[0][1]-m[1][0])< epsilon) 
     && (Math.abs(m[0][2]-m[2][0])< epsilon) 
     && (Math.abs(m[1][2]-m[2][1])< epsilon)) { 
     // singularity found 
     // first check for identity matrix which must have +1 for all terms 
     // in leading diagonaland zero in other terms 
     if ((Math.abs(m[0][1]+m[1][0]) < epsilon2) 
      && (Math.abs(m[0][2]+m[2][0]) < epsilon2) 
      && (Math.abs(m[1][2]+m[2][1]) < epsilon2) 
      && (Math.abs(m[0][0]+m[1][1]+m[2][2]-3) < epsilon2)) { 
      // this singularity is identity matrix so angle = 0 
      return new axisAngle(0,1,0,0); // zero angle, arbitrary axis 
     } 
     // otherwise this singularity is angle = 180 
     angle = Math.PI; 
     double xx = (m[0][0]+1)/2; 
     double yy = (m[1][1]+1)/2; 
     double zz = (m[2][2]+1)/2; 
     double xy = (m[0][1]+m[1][0])/4; 
     double xz = (m[0][2]+m[2][0])/4; 
     double yz = (m[1][2]+m[2][1])/4; 
     if ((xx > yy) && (xx > zz)) { // m[0][0] is the largest diagonal term 
      if (xx< epsilon) { 
       x = 0; 
       y = 0.7071; 
       z = 0.7071; 
      } else { 
       x = Math.sqrt(xx); 
       y = xy/x; 
       z = xz/x; 
      } 
     } else if (yy > zz) { // m[1][1] is the largest diagonal term 
      if (yy< epsilon) { 
       x = 0.7071; 
       y = 0; 
       z = 0.7071; 
      } else { 
       y = Math.sqrt(yy); 
       x = xy/y; 
       z = yz/y; 
      } 
     } else { // m[2][2] is the largest diagonal term so base result on this 
      if (zz< epsilon) { 
       x = 0.7071; 
       y = 0.7071; 
       z = 0; 
      } else { 
       z = Math.sqrt(zz); 
       x = xz/z; 
       y = yz/z; 
      } 
     } 
     return new axisAngle(angle,x,y,z); // return 180 deg rotation 
    } 
    // as we have reached here there are no singularities so we can handle normally 
    double s = Math.sqrt((m[2][1] - m[1][2])*(m[2][1] - m[1][2]) 
     +(m[0][2] - m[2][0])*(m[0][2] - m[2][0]) 
     +(m[1][0] - m[0][1])*(m[1][0] - m[0][1])); // used to normalise 
    if (Math.abs(s) < 0.001) s=1; 
     // prevent divide by zero, should not happen if matrix is orthogonal and should be 
     // caught by singularity test above, but I've left it in just in case 
    angle = Math.acos((m[0][0] + m[1][1] + m[2][2] - 1)/2); 
    x = (m[2][1] - m[1][2])/s; 
    y = (m[0][2] - m[2][0])/s; 
    z = (m[1][0] - m[0][1])/s; 
    return new axisAngle(angle,x,y,z); 
} 
Смежные вопросы