[计算机视觉多视图几何] -- Homography

Homography求解与基于eigen库的c++实现



在这里插入图片描述

前言

在使用标志物识别与跟踪技术中,利用homography来描述两个视图中标志物平面之间的映射关系。

一、理论推导

当两个视图中拥有相同的一个平面时,可以根据平面来估计视图之间的映射关系,并称之为单应性矩阵。

在世界中一个点 P [ X , Y , Z ] P[X,Y,Z] P[X,Y,Z],在两张图像中的位置分别为 p 1 , p 2 p_1,p_2 p1,p2,则有下列关系:
n T P + d = 0 \boldsymbol n^T\boldsymbol P+d=0 nTP+d=0

− n T P d = 1 -\frac{\boldsymbol n^T\boldsymbol P}{d}=1 dnTP=1

同一点在两张视图中的映射关系:
p 1 = K ( P ) \boldsymbol p1 = K(\boldsymbol P) p1=K(P)

p 2 = K ( R P + t ) \boldsymbol p_2=K(\boldsymbol R\boldsymbol P+\boldsymbol t) p2=K(RP+t)

p 2 = K ( R P − t n T P d ) \boldsymbol p_2 = K(\boldsymbol R \boldsymbol P - \boldsymbol t\frac{\boldsymbol n^T\boldsymbol P}{d}) p2=K(RPtdnTP)

p 2 = K ( R − t n T d ) P \boldsymbol p_2 = \boldsymbol K(\boldsymbol R-\boldsymbol t\frac{\boldsymbol n^T}{d})\boldsymbol P p2=K(RtdnT)P

p 2 ∼ K ( R − t n T d ) K − 1 p 1 \boldsymbol p_2 \sim \boldsymbol K(\boldsymbol R-\boldsymbol t\frac{\boldsymbol n^T}{d})\boldsymbol K^{-1}\boldsymbol p_1 p2K(RtdnT)K1p1

所以,化简得到点的映射关系:
p 2 ∼ H p 1 \boldsymbol p_2 \sim \boldsymbol H \boldsymbol p_1 p2Hp1

( u 2 v 2 1 ) ∼ ( h 1 h 2 h 3 h 4 h 5 h 6 h 7 h 8 h 9 ) ( u 1 v 1 1 ) \begin{pmatrix} u_2 \\ v2 \\ 1\end{pmatrix} \sim \begin{pmatrix} h_1& h_2& h_3 \\h_4&h_5&h_6\\h_7&h_8&h_9 \end{pmatrix} \begin{pmatrix} u_1 \\ v_1 \\ 1 \end{pmatrix} u2v21h1h4h7h2h5h8h3h6h9u1v11

u 2 ∼ h 1 u 1 + h 2 v 1 + h 3 u_2 \sim h_1u_1+h_2v_1+h_3 u2h1u1+h2v1+h3

v 2 ∼ h 4 u 1 + h 5 v 1 + h 6 v_2\sim h_4u_1+h_5v_1+h_6 v2h4u1+h5v1+h6

1 ∼ h 7 u 1 + h 8 v 1 + h 9 1\sim h_7u_1+h_8v_1+h_9 1h7u1+h8v1+h9

由于缩放因子的存在,添加一个约束,令 h 9 = 1 h_9=1 h9=1,将矩阵展开得:
h 1 u 1 + h 2 v 1 + h 3 − h 7 u 1 u 2 − h 8 v 1 u 2 = u 2 h_1u_1+h_2v_1+h_3 - h_7u_1u_2 - h_8v_1u_2 = u_2 h1u1+h2v1+h3h7u1u2h8v1u2=u2

h 4 u 1 + h 5 v 1 + h 6 − h 7 u 1 v 2 − h 8 v 1 v 2 = v 2 h_4u_1+h_5v_1+h_6-h_7u_1v_2-h_8v_1v_2=v_2 h4u1+h5v1+h6h7u1v2h8v1v2=v2

( u 1 v 1 1 0 0 0 − u 1 u 2 − v 1 u 2 0 0 0 u 1 v 1 1 − u 1 v 2 − v 1 v 2 ) ( h 1 h 2 h 3 h 4 h 5 h 6 h 7 h 8 ) = ( u 2 v 2 ) \begin{pmatrix} u_1 & v_1&1&0&0&0&-u_1u_2&-v_1u_2\\0&0&0&u_1&v_1&1&-u_1v_2&-v_1v_2 \end{pmatrix} \begin{pmatrix} h_1\\h_2\\h_3\\h_4\\h_5\\h_6\\h_7\\h_8\end{pmatrix}=\begin{pmatrix} u_2\\v_2\\ \end{pmatrix} (u10v10100u10v101u1u2u1v2v1u2v1v2)h1h2h3h4h5h6h7h8=(u2v2)

所以,一对点可以引入两个约束,一共8个未知参数,故需要4对点即可求得映射关系:Ax=B

二、c++实现

1.CMakeLists.txt

cmake_minimum_required(VERSION 3.22.0)
project(homography)

# Eigen
include_directories("/usr/include/eigen3")
add_executable(homography homography.cpp)

2.homography.cpp

void calc_homography(int pts1[4][2], int pts2[4][2], int pts_in[][2], int pts_out[][2])
{
    Eigen::Matrix<float,8,8> A;
    Eigen::Matrix<float,8,1> B;
    for(int i = 0; i<4;++i) {
        A(i*2, 0) = pts1[i][0];
        A(i*2, 1) = pts1[i][1];
        A(i*2, 2) = 1.0;
        A(i*2, 3) = 0.0;
        A(i*2, 4) = 0.0;
        A(i*2, 5) = 0.0;
        A(i*2, 6) = -pts1[i][0] * pts2[i][0];
        A(i*2, 7) = -pts1[i][1] * pts2[i][0];

        A(i*2 + 1, 0) = 0.0;
        A(i*2 + 1, 1) = 0.0;
        A(i*2 + 1, 2) = 0.0;
        A(i*2 + 1, 3) = pts1[i][0];
        A(i*2 + 1, 4) = pts1[i][1];
        A(i*2 + 1, 5) = 1.0;
        A(i*2 + 1, 6) = -pts1[i][0] * pts2[i][1];
        A(i*2 + 1, 7) = -pts1[i][1] * pts2[i][1];
        
        B(i*2, 0) = pts2[i][0];
        B(i*2 + 1, 0) = pts2[i][1];
    }

    std::cout << "求解 Ax=B " << std::endl;
    std::cout << A << "\n" << std::endl;
    std::cout << B.transpose() << "\n" << std::endl;

    Eigen::MatrixXf H = A.colPivHouseholderQr().solve(B);

    Eigen::Matrix<float, 3, 3> X;
    X(0,0) = H(0,0);
    X(0,1) = H(1,0);
    X(0,2) = H(2,0);
    X(1,0) = H(3,0);
    X(1,1) = H(4,0);
    X(1,2) = H(5,0);
    X(2,0) = H(6,0);
    X(2,1) = H(7,0);
    X(2,2) = 1.0;
    std::cout <<"单应性矩阵为" <<std::endl;
    std::cout << X << std::endl;

    Eigen::MatrixXf X_ = X.inverse();
    for(int i=0; i<4; i++)
    {
        Eigen::Matrix<float,3,1> in;
        in << static_cast<float>(pts_in[i][0]), static_cast<float>(pts_in[i][1]), 1;

        Eigen::Matrix<float,3,1> out;
        out = X_ * in;

        pts_out[i][0] = static_cast<int>(out[0]/out[2]);
        pts_out[i][1] = static_cast<int>(out[1]/out[2]);
    }
    std::cout <<"\n" << "N个相机1图像中坐标的点: " << std::endl;
    std::cout << pts_out[0][0] << "   "<< pts_out[0][1] << std::endl;
    std::cout << pts_out[1][0] << "   "<< pts_out[1][1] << std::endl;
    std::cout << pts_out[2][0] << "   "<< pts_out[2][1] << std::endl;
    std::cout << pts_out[3][0] << "   "<< pts_out[3][1] << std::endl;
}

总结

注意由于缩放因子引入的约束。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值