首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单应矩阵分解为旋转矩阵和平移向量

单应矩阵分解为旋转矩阵和平移向量
EN

Stack Overflow用户
提问于 2015-04-22 07:35:08
回答 1查看 4.2K关注 0票数 4

我正在使用opencv 2.4.4为android开发一个增强现实应用程序,在单应性分解方面遇到了一些问题。我们知道,单应矩阵定义为H=A.R t,其中A是本征相机矩阵,R是旋转矩阵,t是平移向量。我想用图片来估计相机的视角,以及3d房间中相机的方向。

单应矩阵我可以估计与opencv函数: findHomography,我认为它的工作!下面是我是如何做到的:

代码语言:javascript
复制
static Mat mFindHomography(MatOfKeyPoint keypoints1, MatOfKeyPoint keypoints2, MatOfDMatch matches){
    List<Point> lp1 = new ArrayList<Point>(500);
    List<Point> lp2 = new ArrayList<Point>(500);

    KeyPoint[] k1 = keypoints1.toArray();
    KeyPoint[] k2 = keypoints2.toArray();

    List<DMatch> matchesList = matches.toList();

    if (matchesList.size() < 4){
        MatOfDMatch mat = new MatOfDMatch();
        return mat;
    }

    // Add matches keypoints to new list to apply homography
    for(DMatch match : matchesList){
        Point kk1 = k1[match.queryIdx].pt;
        Point kk2 = k2[match.trainIdx].pt;
        lp1.add(kk1);
        lp2.add(kk2);
    }

    MatOfPoint2f srcPoints = new MatOfPoint2f(lp1.toArray(new Point[0]));
    MatOfPoint2f dstPoints  = new MatOfPoint2f(lp2.toArray(new Point[0]));

    Mat mask = new Mat();

    Mat homography = Calib3d.findHomography(srcPoints, dstPoints, Calib3d.RANSAC, 10, mask); // Finds a perspective transformation between two planes. ---Calib3d.LMEDS Least-Median robust method 

    List<DMatch> matches_homo = new ArrayList<DMatch>();
    int size = (int) mask.size().height;
    for(int i = 0; i < size; i++){          
        if ( mask.get(i, 0)[0] == 1){
            DMatch d = matchesList.get(i);
            matches_homo.add(d);
        }
    }

    MatOfDMatch mat = new MatOfDMatch();
    mat.fromList(matches_homo);

    matchesFilterdByRansac = (int) mat.size().height;
    return homography;
}

然后,我想分解这个单应矩阵并计算euler角。正如我们知道的那样,我将单应矩阵乘以相机内部矩阵的逆矩阵: H.A^{-1} =R。所以,我想要在旋转和平移中分解R,并从旋转矩阵计算欧拉角。但它并没有起作用。这是怎么了?!!

代码语言:javascript
复制
if(!homography.empty()){ // esstimate pose frome homography 
Mat intrinsics = Mat.zeros(3, 3, CvType.CV_32FC1);  // camera intrinsic matrix 
intrinsics.put(0, 0, 890);
intrinsics.put(0, 2, 400);
intrinsics.put(1, 1, 890);
intrinsics.put(1, 2, 240);
intrinsics.put(2, 2, 1);

// Inverse Matrix from Wolframalpha
double[] inverseIntrinsics = { 0.001020408, 0 , -0.408163265,
        0, 0.0011235955, -0.26966292,
        0, 0 , 1 }; 

// cross multiplication 
double[] rotationTranslation = matrixMultiply3X3(homography, inverseIntrinsics);

Mat pose = Mat.eye(3, 4, CvType.CV_32FC1);  // 3x4 matrix, the camera pose
float norm1 = (float) Core.norm(rotationTranslation.col(0));
float norm2 = (float) Core.norm(rotationTranslation.col(1));
float tnorm = (norm1 + norm2) / 2.0f;       // Normalization value  ---test: float tnorm = (float) h.get(2, 2)[0];// not worked

Mat normalizedTemp = new Mat();
Core.normalize(rotationTranslation.col(0), normalizedTemp);
normalizedTemp.convertTo(normalizedTemp, CvType.CV_32FC1);
normalizedTemp.copyTo(pose.col(0)); // Normalize the rotation, and copies the column to pose

Core.normalize(rotationTranslation.col(1), normalizedTemp);
normalizedTemp.convertTo(normalizedTemp, CvType.CV_32FC1);    
normalizedTemp.copyTo(pose.col(1));// Normalize the rotation and copies the column to pose

Mat p3 = pose.col(0).cross(pose.col(1)); // Computes the cross-product of p1 and p2
p3.copyTo(pose.col(2));// Third column is the crossproduct of columns one and two

double[] buffer = new double[3];
rotationTranslation.col(2).get(0, 0, buffer);
pose.put(0, 3, buffer[0] / tnorm);  //vector t [R|t] is the last column of pose
pose.put(1, 3, buffer[1] / tnorm);
pose.put(2, 3, buffer[2] / tnorm);

float[] rotationMatrix = new float[9];
rotationMatrix = getArrayFromMat(pose);

float[] eulerOrientation = new float[3];
SensorManager.getOrientation(rotationMatrix, eulerOrientation); 

// Convert radian to degree
double yaw = (double) (eulerOrientation[0]) * (180 / Math.PI));// * -57;
double pitch = (double) (eulerOrientation[1]) * (180 / Math.PI));
double roll = (double) (eulerOrientation[2]) * (180 / Math.PI));}

请注意,OpenCV3.0有一个同源分解函数(here),但我使用的是opencv 2.4.4 for android!在java中有包装器吗?

第二个问题是欧拉角中旋转矩阵的分解。是否存在以下问题:

代码语言:javascript
复制
    float[] eulerOrientation = new float[3];
SensorManager.getOrientation(rotationMatrix, eulerOrientation); 

我也用了这个link,但效果并不好!

代码语言:javascript
复制
double pitch = Math.atan2(pose.get(2, 1)[0], pose.get(2, 2)[0]);
double roll = Math.atan2(-1*pose.get(2, 0)[0], Math.sqrt( Math.pow(pose.get(2, 1)[0], 2) + Math.pow(pose.get(2, 2)[0], 2)) );
double yaw = Math.atan2(pose.get(1, 0)[0], pose.get(0, 0)[0]);

非常感谢您的回复

EN

回答 1

Stack Overflow用户

发布于 2018-02-15 21:02:50

我希望这个答案能帮助那些今天正在寻找解决方案的人。

我的答案是使用c++和opencv 2.4.9。我复制了opencv 3.0中的分解同形映射函数。在计算单应性之后,我使用复制的函数来分解单应性。要过滤单应矩阵并从4个分解中选择正确答案,请查看my answer here

要从旋转矩阵中获得欧拉角,可以参考this。用这种方法我能得到很好的结果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29785049

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档