点云刚体配准,并计算误差

#include <vector>
#include <Eigen/Core>
#include <Eigen/Eigen>
#include <Eigen/Geometry>

Eigen::MatrixXd repmat(Eigen::MatrixXd matrix, int row, int col)
{
    Eigen::MatrixXd matrixExtend;
    if (row < 1 || col < 1)
    {
        return matrixExtend;
    }

    int extend_rows = matrix.rows();
    int extend_cols = matrix.cols();

    matrixExtend = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>();//动态矩阵初始化

    matrixExtend.resize(matrix.rows(), matrix.cols());
    matrixExtend = matrix;
    for (int colExtend = 1; colExtend < col; colExtend++)
    {
        extend_cols = extend_cols + matrix.cols();
        Eigen::MatrixXd matrixTemp;
        matrixTemp = matrixExtend;
        matrixExtend.resize(extend_rows, extend_cols);//改变要扩展矩阵的维度
        matrixExtend << matrixTemp, matrix;
    }

    Eigen::MatrixXd matrixRow;
    matrixRow = matrixExtend;
    for (int rowExtend = 1; rowExtend < row; rowExtend++)
    {
        extend_rows = extend_rows + matrix.rows();
        Eigen::MatrixXd matrixTemp;
        matrixTemp = matrixExtend;
        matrixExtend.resize(extend_rows, extend_cols);//改变要扩展矩阵的维度
        matrixExtend << matrixTemp, matrixRow;
    }

    return matrixExtend;
}



Eigen::Matrix4d Regist(std::vector<double> srcdata, std::vector<double> dstdata, double& err )
{
    //深度拷贝原始数据 原因是 Eigen 去质心 会修改原始数据
    int col = 3;
    int row = srcdata.size()/3;
    int N = srcdata.size()/3;
    // SVD计算点集配准,输入两个对应点云,输出旋转矩阵、平移向量
    Eigen::MatrixXd src = Eigen::Map<Eigen::MatrixXd>(srcdata.data(), col, row).transpose();
    Eigen::MatrixXd dst = Eigen::Map<Eigen::MatrixXd>(dstdata.data(), col, row).transpose();

    // 1、计算质心
    Eigen::RowVector3d srcMean = src.colwise().mean();  // 每列求均值
    Eigen::RowVector3d tarMean = dst.colwise().mean();
    // 2、去质心
    Eigen::MatrixXd A = src.rowwise() - srcMean;
    Eigen::MatrixXd B = dst.rowwise() - tarMean;
    // 3、构建协方差矩阵
    Eigen::Matrix3d covMat = (A.transpose() * B) / A.rows();
    // 4、SVD分解求旋转矩阵
    Eigen::JacobiSVD<Eigen::MatrixXd> svd(covMat, Eigen::ComputeFullU | Eigen::ComputeFullV);
    Eigen::MatrixXd V = svd.matrixV();
    Eigen::MatrixXd U = svd.matrixU();
    Eigen::MatrixXd R =  V * U.transpose() ;

    //通过检查R的行列式(来自上面的SVD)并查看它是否为负(-1)可以解决这个问题。如果是,则 V 的第 3 列乘以 -1。
    double det  = R.determinant() < 0? -1: 1;
    Eigen::MatrixXd matM = Eigen::Matrix3d::Identity();
    matM<<1, 0, 0,
          0, 1, 0,
          0, 0, det;
    R =  V * matM * U.transpose() ;

    // 5、求平移向量
    Eigen::MatrixXd T = tarMean.transpose() - R* srcMean.transpose();

    Eigen::MatrixXd matrix = Eigen::Matrix4d::Identity();
    matrix.block<3,3>(0,0) = R;
    matrix.block<3,1>(0,3) = T;

    Eigen::MatrixXd inpB = (R * src.transpose() + repmat(T, 1, N)).transpose();

//    std::cout<<"Regist Matrix\n"<<matrix<<std::endl<<std::endl;
//    std::cout<<"Regist inpB: \n"<<inpB<<std::endl<<std::endl;
    err = 0.0;
    for (size_t i = 0; i < N; ++i)
    {
        auto distance =  (dst.row(i) - inpB.row(i)).norm();
        err += distance * distance;
    }
    err = sqrt(err/N);
//    std::cout<<"err: "<<err<<std::endl<<std::endl;
    return matrix;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值