Android& OpenCV:考虑相机内在和反投影的同形相机姿势

时间:2013-06-10 15:20:14

标签: android opencv tracking homography

Libs:OpenCV 目标:Android(OpenCV4Android)

我尝试计算世界平面的Homography(例如监视器屏幕)以获取相机姿势,对其进行转换并重新投影点以进行跟踪任务。 我正在使用OpenCVs findHomography()/ getPerspectiveTransform()来获得单应性。使用perspectiveTransform()(如此处所解释的:http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html)重新投影点,这非常有效。 “screenPoints”是监视器边缘的世界坐标(使用纵横比和z值为0),“imagePoints”是图像中屏幕边缘的x / y坐标。

Mat homography = org.opencv.imgproc.Imgproc.getPerspectiveTransform(screenPoints, imagePoints);

我有相机校准矩阵(我已经使用了matlab校准工具箱),我发现了一个提示(在评论@ https://dsp.stackexchange.com/questions/2736/step-by-step-camera-pose-estimation-for-visual-tracking-and-planar-markers中),用于考虑单应性中的相机参数。

H'= K ^ -1 * H

(H' - Homography-Matrix考虑相机校准,H - Homography-Matrix,K ^ -1 - 逆相机校准矩阵)。

Mat intrinsicInverse = new Mat(3, 3, CvType.CV_32FC1);
Core.invert(intrinsic, intrinsicInverse);
intrinsicInverse.convertTo(intrinsicInverse, CvType.CV_32FC1);          
homography.convertTo(homography, CvType.CV_32FC1);
// compute H respect the intrinsics
Core.gemm(intrinsicInverse, homography, 1, new Mat(), 0, homography);

我的下一步是根据此处的Computing camera pose with homography matrix based on 4 coplanar points来计算单应性的相机姿势。

因为即时尝试在Android上执行此操作,我必须将C ++代码移植到Java:

private Mat cameraPoseFromHomography(Mat h) {
    Log.d("DEBUG", "cameraPoseFromHomography: homography " + matToString(h));

    Mat pose = Mat.eye(3, 4, CvType.CV_32FC1);  // 3x4 matrix, the camera pose
    float norm1 = (float) Core.norm(h.col(0));
    float norm2 = (float) Core.norm(h.col(1));
    float tnorm = (norm1 + norm2) / 2.0f;       // Normalization value

    Mat normalizedTemp = new Mat();
    Core.normalize(h.col(0), normalizedTemp);
    normalizedTemp.convertTo(normalizedTemp, CvType.CV_32FC1);
    normalizedTemp.copyTo(pose.col(0));

    Core.normalize(h.col(1), normalizedTemp);
    normalizedTemp.convertTo(normalizedTemp, CvType.CV_32FC1);    
    normalizedTemp.copyTo(pose.col(1));

    Mat p3 = pose.col(0).cross(pose.col(1));
    p3.copyTo(pose.col(2));

    Mat temp = h.col(2);
    double[] buffer = new double[3];
    h.col(2).get(0, 0, buffer);
    pose.put(0, 3, buffer[0] / tnorm);
    pose.put(1, 3, buffer[1] / tnorm);
    pose.put(2, 3, buffer[2] / tnorm);

    return pose;
}

我无法检查代码是否正在做正确的事情,但它正在运行。 在这一点上,我假设考虑到相机校准而拥有完整的相机姿势。

如此处http://opencv.willowgarage.com/documentation/python/calib3d_camera_calibration_and_3d_reconstruction.html#rodrigues2所述,3D点的重投影只是

p = K * CP * P

(p - 2D位置,K - 校准矩阵,CP - 相机姿态,P - 3D点)

    Core.gemm(intrinsic, cameraPosition, 1, new Mat(), 0, vec4t);
    Core.gemm(vec4t, point, 1, new Mat(), 0, result);

结果远离屏幕边缘的源图像位置。但我可以通过它的相对差异来识别所有三个边缘 - 所以它可能只是一些错误的因素。

这是我第一次做这样的计算机视觉任务,而且我可能做了一些基本上错了。我有来自Zisserman的“多视图几何”一书,我阅读了所有相关部分 - 但说实话 - 我没有得到大部分内容。

更新

在我的相机矩阵中发现了一个错误 - 上面的实现工作正常!

2 个答案:

答案 0 :(得分:1)

让它以另一种方式工作。而不是使用findHomography()/ getP erspectiveTransform()我找到了另一个名为solvePnP()的函数,它根据世界和图像点以及内在的相机矩阵返回相机姿势。

将该功能与projectPoints()方法结合使用 - 我能够将3d点重新投影回图像。

如果屏幕边缘位于图像的右侧位置。

<强>更新

我在实现中发现了一个错误 - 我的相机内在矩阵错了。上面的单应性实现的相机姿势对我有用!

答案 1 :(得分:0)

校准案例(H)中的Homography与未校准案例(H')之间的关系是

H'= ^( - 1),其中K是相机的内在矩阵。