48

我在视频(或图像)中有 4 个共面点,代表一个四边形(不一定是正方形或矩形),我希望能够在它们上面显示一个虚拟立方体,其中立方体的角正好位于角上的视频四边形。

由于这些点是共面的,我可以计算单位正方形的角(即 [0,0] [0,1] [1,0] [1,1])和四边形的视频坐标之间的单应性。

根据这个单应性,我应该能够计算出正确的相机位姿,即 [R|t],其中 R 是 3x3 旋转矩阵,t 是 3x1 平移向量,因此虚拟立方体位于视频四边形上。

我已经阅读了许多解决方案(其中一些在 SO 上)并尝试实现它们,但它们似乎只适用于一些“简单”的情况(比如视频四边形是正方形时),但在大多数情况下不起作用。

以下是我尝试过的方法(大部分都是基于相同的原理,只是翻译的计算略有不同)。令 K 为来自相机的内在矩阵,H 为单应矩阵。我们计算:

A = K-1 * H

令 a1,a2,a3 为 A 的列向量,r1,r2,r3 为旋转矩阵 R 的列向量。

r1 = a1 / ||a1||
r2 = a2 / ||a2||
r3 = r1 x r2
t = a3 / sqrt(||a1||*||a2||)

问题是这在大多数情况下不起作用。为了检查我的结果,我将 R 和 t 与 OpenCV 的 solvePnP 方法(使用以下 3D 点 [0,0,0] [0,1,0] [1,0,0] [1,1 ,0])。

由于我以相同的方式显示立方体,我注意到在每种情况下 solvePnP 都提供了正确的结果,而从单应性获得的姿势大多是错误的。

理论上,由于我的点是共面的,因此可以从单应性计算姿势,但我找不到从 H 计算姿势的正确方法。

关于我做错了什么的任何见解?

尝试@Jav_Rock 的方法后编辑

嗨 Jav_Rock,非常感谢您的回答,我尝试了您的方法(以及许多其他方法),这似乎或多或少都可以。尽管如此,在基于 4 个共面点计算姿势时,我仍然碰巧遇到了一些问题。为了检查结果,我与 solvePnP 的结果进行了比较(由于迭代重投影误差最小化方法,这会好得多)。

这是一个例子:

立方体

  • 黄色方块:解决 PNP
  • Black Cube:Jav_Rock 的技术
  • 青色(和紫色)立方体:给出完全相同结果的其他一些技术

如您所见,黑色立方体或多或少还可以,但看起来比例不太好,尽管向量看起来是正交的。

EDIT2:我在计算 v3 之后对其进行了归一化(为了强制正交性),它似乎也解决了一些问题。

4

7 回答 7

32

如果你有你的 Homography,你可以用这样的东西计算相机姿势:

void cameraPoseFromHomography(const Mat& H, Mat& pose)
{
    pose = Mat::eye(3, 4, CV_32FC1);      // 3x4 matrix, the camera pose
    float norm1 = (float)norm(H.col(0));  
    float norm2 = (float)norm(H.col(1));  
    float tnorm = (norm1 + norm2) / 2.0f; // Normalization value

    Mat p1 = H.col(0);       // Pointer to first column of H
    Mat p2 = pose.col(0);    // Pointer to first column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation, and copies the column to pose

    p1 = H.col(1);           // Pointer to second column of H
    p2 = pose.col(1);        // Pointer to second column of pose (empty)

    cv::normalize(p1, p2);   // Normalize the rotation and copies the column to pose

    p1 = pose.col(0);
    p2 = pose.col(1);

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

    pose.col(3) = H.col(2) / tnorm;  //vector t [R|t] is the last column of pose
}

这种方法对我有效。祝你好运。

于 2012-05-28T07:54:59.273 回答
11

Jav_Rock 提出的答案并没有为三维空间中的相机姿势提供有效的解决方案。

为了估计由单应性引起的树维变换和旋转,存在多种方法。其中之一提供了分解单应性的封闭公式,但它们非常复杂。此外,解决方案从来都不是唯一的。

幸运的是,OpenCV 3 已经实现了这种分解(decomposeHomographyMat)。给定单应性和正确缩放的内在矩阵,该函数提供一组四种可能的旋转和平移。

于 2015-07-09T15:43:19.093 回答
9

以防万一有人需要 @Jav_Rock 编写的函数的 python 移植:

def cameraPoseFromHomography(H):
    H1 = H[:, 0]
    H2 = H[:, 1]
    H3 = np.cross(H1, H2)

    norm1 = np.linalg.norm(H1)
    norm2 = np.linalg.norm(H2)
    tnorm = (norm1 + norm2) / 2.0;

    T = H[:, 2] / tnorm
    return np.mat([H1, H2, H3, T])

在我的任务中工作正常。

于 2014-11-25T23:47:19.600 回答
9

从单应矩阵计算 [R|T] 比 Jav_Rock 的答案稍微复杂一些。

在 OpenCV 3.0 中,有一个名为 cv::decomposeHomographyMat 的方法返回四个潜在的解决方案,其中一个是正确的。但是,OpenCV 没有提供一种方法来挑选出正确的方法。

我现在正在研究这个,也许会在本月晚些时候在这里发布我的代码。

于 2015-05-14T05:43:56.890 回答
0

图像上包含您的 Square 的平面具有消失的车道代理您的相机。这条线的方程是A x+B y+C=0。

你的飞机的法线是(A,B,C)!

令 p00,p01,p10,p11 是应用相机的内在参数后的点坐标,并且是齐次形式,例如,p00=(x00,y00,1)

消失线可以计算为:

  • 向下 = p00 交叉 p01;
  • 左 = p00 交叉 p10;
  • 右 = p01 交叉 p11;
  • 向上 = p10 交叉 p11;
  • v1=左交叉右;
  • v2=向上交叉向下;
  • vanish_line = v1 交叉 v2;

标准向量叉积中的交叉

于 2016-07-18T14:17:03.367 回答
0

你可以使用这个功能。为我工作。

def find_pose_from_homography(H, K):
    '''
    function for pose prediction of the camera from the homography matrix, given the intrinsics 
    
    :param H(np.array): size(3x3) homography matrix
    :param K(np.array): size(3x3) intrinsics of camera
    :Return t: size (3 x 1) vector of the translation of the transformation
    :Return R: size (3 x 3) matrix of the rotation of the transformation (orthogonal matrix)
    '''
    
    
    #to disambiguate two rotation marices corresponding to the translation matrices (t and -t), 
    #multiply H by the sign of the z-comp on the t-matrix to enforce the contraint that z-compoment of point
    #in-front must be positive and thus obtain a unique rotational matrix
    H=H*np.sign(H[2,2])

    h1,h2,h3 = H[:,0].reshape(-1,1), H[:,1].reshape(-1,1) , H[:,2].reshape(-1,1)
    
    R_ = np.hstack((h1,h2,np.cross(h1,h2,axis=0))).reshape(3,3)
    
    U, S, V = np.linalg.svd(R_)
    
    R = U@np.array([[1,0,0],
                   [0,1,0],
                    [0,0,np.linalg.det(U@V.T)]])@V.T
    
    t = (h3/np.linalg.norm(h1)).reshape(-1,1)
    
    return R,t
于 2020-12-20T19:53:48.533 回答
-1

这是一个 python 版本,基于 Dmitriy Voloshyn 提交的版本,它对旋转矩阵进行归一化并将结果转置为 3x4。

def cameraPoseFromHomography(H):  
    norm1 = np.linalg.norm(H[:, 0])
    norm2 = np.linalg.norm(H[:, 1])
    tnorm = (norm1 + norm2) / 2.0;

    H1 = H[:, 0] / norm1
    H2 = H[:, 1] / norm2
    H3 = np.cross(H1, H2)
    T = H[:, 2] / tnorm

    return np.array([H1, H2, H3, T]).transpose()
于 2015-03-09T01:54:40.707 回答