首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >找出两组点的平移和尺度,从而得到距离上的最小平方误差?

找出两组点的平移和尺度,从而得到距离上的最小平方误差?
EN

Stack Overflow用户
提问于 2012-11-17 17:15:08
回答 7查看 22.9K关注 0票数 22

我有两组3D点(原始的和重构的)和关于对的对应信息--从一组中的点代表第二组。我需要找到3D平移和缩放因子来转换重建集,使平方距离之和最小(旋转也很好,但是点也是同样旋转的,所以这不是主要的优先级,为了简单和速度,这可能被省略)。所以我的问题是--这个问题在互联网上得到解决了吗?就我个人而言,我会使用最小二乘法,但我没有太多的时间(虽然我有点擅长数学,但我不经常使用它,所以最好避免它),所以如果它存在的话,我想使用别人的解决方案。我更喜欢C++中的解决方案,例如使用OpenCV,但是算法本身就足够好了。

如果没有这样的解决方案,我会自己计算,我不想打扰你这么多。

解决方案:(来自您的答案)

对我来说,这是一种卡布希算法;

基本信息:算法

通用解决方案:id=671

还没有解决:我也需要规模。SVD的标度值对我来说是不可理解的;当我需要所有轴的1-4标度时(据我估计),SVD的标度约为2000,200,20,这一点也没有帮助。

EN

回答 7

Stack Overflow用户

发布于 2015-08-27 08:53:53

既然您已经在使用Kabsch,那么只需看一看Umeyama论文,它就可以扩展它以获得扩展。你所需要做的就是得到你的点的标准差,并计算标度如下:

代码语言:javascript
复制
(1/sigma^2)*trace(D*S)

其中,D是旋转估计中奇异值分解中的对角矩阵,S是单位矩阵或[1 1 -1]对角矩阵,这取决于UV行列式的符号(UV用于校正反射到适当的旋转)。所以如果你有[2000, 200, 20],把最后一个元素乘以+-1 (取决于UV行列式的符号),把它们加起来,除以点的标准差,得到标度。

可以循环使用本征库的下列代码:

代码语言:javascript
复制
typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vector3d_U; // microsoft's 32-bit compiler can't put Eigen::Vector3d inside a std::vector. for other compilers or for 64-bit, feel free to replace this by Eigen::Vector3d

/**
 *  @brief rigidly aligns two sets of poses
 *
 *  This calculates such a relative pose <tt>R, t</tt>, such that:
 *
 *  @code
 *  _TyVector v_pose = R * r_vertices[i] + t;
 *  double f_error = (r_tar_vertices[i] - v_pose).squaredNorm();
 *  @endcode
 *
 *  The sum of squared errors in <tt>f_error</tt> for each <tt>i</tt> is minimized.
 *
 *  @param[in] r_vertices is a set of vertices to be aligned
 *  @param[in] r_tar_vertices is a set of vertices to align to
 *
 *  @return Returns a relative pose that rigidly aligns the two given sets of poses.
 *
 *  @note This requires the two sets of poses to have the corresponding vertices stored under the same index.
 */
static std::pair<Eigen::Matrix3d, Eigen::Vector3d> t_Align_Points(
    const std::vector<Vector3d_U> &r_vertices, const std::vector<Vector3d_U> &r_tar_vertices)
{
    _ASSERTE(r_tar_vertices.size() == r_vertices.size());
    const size_t n = r_vertices.size();

    Eigen::Vector3d v_center_tar3 = Eigen::Vector3d::Zero(), v_center3 = Eigen::Vector3d::Zero();
    for(size_t i = 0; i < n; ++ i) {
        v_center_tar3 += r_tar_vertices[i];
        v_center3 += r_vertices[i];
    }
    v_center_tar3 /= double(n);
    v_center3 /= double(n);
    // calculate centers of positions, potentially extend to 3D

    double f_sd2_tar = 0, f_sd2 = 0; // only one of those is really needed
    Eigen::Matrix3d t_cov = Eigen::Matrix3d::Zero();
    for(size_t i = 0; i < n; ++ i) {
        Eigen::Vector3d v_vert_i_tar = r_tar_vertices[i] - v_center_tar3;
        Eigen::Vector3d v_vert_i = r_vertices[i] - v_center3;
        // get both vertices

        f_sd2 += v_vert_i.squaredNorm();
        f_sd2_tar += v_vert_i_tar.squaredNorm();
        // accumulate squared standard deviation (only one of those is really needed)

        t_cov.noalias() += v_vert_i * v_vert_i_tar.transpose();
        // accumulate covariance
    }
    // calculate the covariance matrix

    Eigen::JacobiSVD<Eigen::Matrix3d> svd(t_cov, Eigen::ComputeFullU | Eigen::ComputeFullV);
    // calculate the SVD

    Eigen::Matrix3d R = svd.matrixV() * svd.matrixU().transpose();
    // compute the rotation

    double f_det = R.determinant();
    Eigen::Vector3d e(1, 1, (f_det < 0)? -1 : 1);
    // calculate determinant of V*U^T to disambiguate rotation sign

    if(f_det < 0)
        R.noalias() = svd.matrixV() * e.asDiagonal() * svd.matrixU().transpose();
    // recompute the rotation part if the determinant was negative

    R = Eigen::Quaterniond(R).normalized().toRotationMatrix();
    // renormalize the rotation (not needed but gives slightly more orthogonal transformations)

    double f_scale = svd.singularValues().dot(e) / f_sd2_tar;
    double f_inv_scale = svd.singularValues().dot(e) / f_sd2; // only one of those is needed
    // calculate the scale

    R *= f_inv_scale;
    // apply scale

    Eigen::Vector3d t = v_center_tar3 - (R * v_center3); // R needs to contain scale here, otherwise the translation is wrong
    // want to align center with ground truth

    return std::make_pair(R, t); // or put it in a single 4x4 matrix if you like
}
票数 23
EN

Stack Overflow用户

发布于 2014-08-09 23:02:46

对于三维点,这个问题被称为绝对方向问题。c++实现可以从特征Module.html#gab3f5a82a24490b936f8694cf8fef8e60和纸张http://web.stanford.edu/class/cs273/refs/umeyama.pdf中获得。

您可以通过opencv使用cv::cv2eigen()调用将矩阵转换为特征。

票数 7
EN

Stack Overflow用户

发布于 2012-11-18 04:37:35

一个很好的解释寻找最佳旋转和对应三维点之间的平移

代码在matlab中,但是使用cv::SVD函数将代码转换为opengl非常简单

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

https://stackoverflow.com/questions/13432805

复制
相关文章

相似问题

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