V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DIMOJANG
V2EX  ›  OpenCV

请问一个关于 OpenCV 手眼标定(cv::calibrateHandEye)获取相机安装参数的问题

  •  
  •   DIMOJANG · 118 天前 · 1248 次点击
    这是一个创建于 118 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我有一台固定在云台上的相机,我想要知道这个相机相对安装平台的旋转和平移量。其中云台是固定不动的,只有 pitch 、yaw 、和 roll 轴的运动。查了一下应该是用这个函数:

    void calibrateHandEye(
        InputArrayOfArrays R_gripper2base,  // 云台 p y r 角度转换出来的旋转矩阵
        InputArrayOfArrays t_gripper2base,  // 输入的是 0 ,因为没有任何移动(并且想用云台平台当世界坐标中心点)
        InputArrayOfArrays R_target2cam,    // calibrateCamera 输出的 rvec
        InputArrayOfArrays t_target2cam,    // calibrateCamera 输出的 tvec
        OutputArray R_cam2gripper, 
        OutputArray t_cam2gripper, 
        HandEyeCalibrationMethod method = CALIB_HAND_EYE_TSAI)
    

    我现在是这样做的:

    1. 将云台的 p y r 旋转到不同角度,拍摄棋盘格的照片,同时记录该时刻的 p y r 角旋转角度;
    2. 使用 calibrateCamera 得到每一张图片里棋盘格的 tvec 和 rvec ;
    3. 将记录的云台 p y r 角度转换为旋转矩阵;
    4. 调用 calibrateHandEye 。

    但是结果和实际相差巨大。因此想来 V 站看看有没有人有过这方面经验,能看出我的步骤里可能有什么问题……先在这里谢过各位了!


    我个人感觉比较容易出问题的地方是第三步的转换,我是这样写的:

        Eigen::Quaternionf euler2quaternionf(const float z, const float y, const float x)
        {
            const float cos_z = cos(z * 0.5f), sin_z = sin(z * 0.5f),
                        cos_y = cos(y * 0.5f), sin_y = sin(y * 0.5f),
                        cos_x = cos(x * 0.5f), sin_x = sin(x * 0.5f);
    
            Eigen::Quaternionf quaternion(
                cos_z * cos_y * cos_x + sin_z * sin_y * sin_x,
                cos_z * cos_y * sin_x - sin_z * sin_y * cos_x,
                sin_z * cos_y * sin_x + cos_z * sin_y * cos_x,
                sin_z * cos_y * cos_x - cos_z * sin_y * sin_x
            );
    
            return quaternion;
        }
    
    

    先转换为四元数,再求旋转矩阵(用 Eigen 自带的方法)。

    3 条回复    2024-08-14 14:47:48 +08:00
    Insolitude
        1
    Insolitude  
       112 天前 via Android
    可能的原因,opencv 很喜欢追求小的误差,导致整个旋转平移矩阵变的非常离谱,比如把坐标中心移出去个几米,再把坐标系转回来。
    解决方法可能就一个位置多取点数据。(我以前有个类似的项目是用 pytorch 撸了个相机投影的全过程,不考虑畸变也就一堆矩阵乘法,像神经网络一样训练,效果居然还行
    MCVector
        2
    MCVector  
       112 天前
    我认为传入的平移矩阵不一定为单位矩阵,除非旋转的轴一直在 cmos 的中心。不过应该不会造成巨大差异。
    另外欧拉角应该直接可以转换为矩阵形式,不需要预先转换成四元数。四元数的作用一般是为了更平滑地插值。https://en.wikipedia.org/wiki/Euler_angles#Conversion_to_other_orientation_representations
    https://eigen.tuxfamily.org/dox/group__TutorialGeometry.html#title3
    希望有所帮助。
    DIMOJANG
        3
    DIMOJANG  
    OP
       99 天前
    @Insolitude #1 请问一下您提到的第一点是否有相关的参考来源?我后面误打误撞对同一个云台姿态进行多次采样确实获得了更理想的结果。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3037 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 13:30 · PVG 21:30 · LAX 05:30 · JFK 08:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.