双目相机标定结果内参及外参验证

本文围绕双目相机标定结果验证展开,介绍在OpenGL中重投影目标模型到图像平面的方法。先阐述相机标定重要性及所用棋盘格标定法,接着说明拍摄图片、单独标定左右相机图片的过程,重点讲解验证标定结果,涉及坐标系转换、矩阵对应等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

双目相机标定结果(内参,外参)验证–在OpenGL中重投影目标模型到图像平面,与左右视角图像中的模型同时重合

相机标定是计算机视觉任务中比较基础且重要的前提步骤。单目相机的标定可以直接用来对图像进行反扭曲处理。多目相机标定稍微复杂一些,笔者这里在做多目姿态估计的任务,因此接触到了多目相机标定。

我这里用到的方法也很简单,用的是比较经典的棋盘格标定法。两个相机设置一定的拍摄角度,同时拍摄若干组标定板的图片,保证相机至少有几张是同时看到标定板的(方便之后的标定验证)。标定工具用的是GML C++ Camera Calibration Toolbox,也可以用Camera Calibration Toolbox for Matlab。两个工具标定后都会给出一个反投影误差,用来评估标定的准确性。

如果标定结果足够精确,那么在一个视角下使目标模型与图片模型重合,其他视角下也会重合。基于这个前提,做下面的任务。项目地址
1 拍摄图片
2 单独标定左右相机图片
3 验证标定结果
1 拍摄图片 (图片中的手部模型为3D打印,OpenGL中会绘制相同的模型)

简易做了一个标定版,A4纸打印,8*5 size的pattern,格子边长为27.5mm。分别拍摄两个视角下的图片若干张。我这里保证left 和right 视角下各有两张是同时拍到标定板的。
在这里插入图片描述

2 单独标定左右相机图片

笔者用GML标定工具,并且分别导出了内参矩阵和外参矩阵。具体的标定结果可在这里下载。

3 验证标定结果

接下来才是这篇博客的重点。这里我贴出几个自己参考的blog。1:3D Projection 2:Augmented Reality on libQGLViewer and OpenCV-OpenGL tips [w/code] 3:Camera Models and Augmented Reality

关于标定的原理,大家可以查询相关知识,这里不再赘述。我们的主要目的就是验证内参和外参。如下公式所示。

OpenCV中相机坐标系为右手坐标系,转换到OpenGL相机坐标系要进行z轴的反转。
相机内参矩阵对应OpenGL的投影矩阵,外参矩阵对应OpenGL的ModelView矩阵。费话不多说,直接来看代码,读取GML标定结果,并且构造Projection 和 View 矩阵。

以下为初始化变量的声明,其中用到了自己写的简单的OpenGL库,可参考项目地址查看

from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
from GEngine.shader import ShaderProgram
from GEngine.model import Model, ModelFromExport, generate_grid_mesh
import glm
from GEngine.camera3D import Camera3D
from GEngine.input_process import InputProcess, keys
from GEngine.window import GWindow
import cv2

camera = Camera3D(glm.vec3(0.0, 5.0, 30.0))
window = GWindow(b"demo", SCR_WIDTH, SCR_HEIGHT, InputProcess(camera, SCR_WIDTH, SCR_HEIGHT), keep_mouse_stay=False)

image_size = (1920, 1080)
light_color = (1.0, 1.0, 1.0)
hand_color = (0.9, 0.9, 0.9)
light_position = (-1000, -700, 1000)

model_position = [
    glm.vec3(1.0, 1.0, 1.0),
    [[0, glm.vec3(1.0, 0.0, 0.0)], [0, glm.vec3(0.0, 1.0, 0.0)], [0, glm.vec3(0.0, 0.0, 1.0)]],
    glm.vec3(500, 500.0, 0.0)
]
image_path = "/media/shuai/SHUAI_AHUT/calibration_same_camera/"

left_camera_intrinsic = np.loadtxt(image_path + "left/Intrinsic.txt")
right_camera_intrinsic = np.loadtxt(image_path + "/right/Intrinsic.txt")

left_camera_extrinsic = np.loadtxt(image_path + "left/ExtrinsicCameraPars.txt")
right_camera_extrinsic = np.loadtxt(image_path + "right/ExtrinsicCameraPars.txt")
# 构造projection矩阵
def build_projection_matrix(camera_intrinsic_matrix, width, height):
    d_near = 0.1  # Near clipping distance
    d_far = 1000.0  # Far clipping distance

    # Camera parameters
    fx = camera_intrinsic_matrix[0, 0]  # Focal length in x axis
    fy = camera_intrinsic_matrix[1, 1]  # Focal length in y axis (usually the same?)
    cx = camera_intrinsic_matrix[0, 2]  # Camera primary point x
    cy = camera_intrinsic_matrix[1, 2]  # Camera primary point y

    projection_matrix = np.array([[fx / cx, 0.0, 0.0, 0.0],
                                  [0.0, fy / cy, 0.0, 0.0],
                                  [0, 0, -(d_far + d_near) / (d_far - d_near), -1.0],
                                  [0.0, 0.0, -2.0 * d_far * d_near / (d_far - d_near), 0.0]], dtype=np.float32)


    return projection_matrix

# 构造view矩阵
def build_model_view_matrix(camera_extrinsic_matrix):
    r, t = camera_extrinsic_matrix[3:], camera_extrinsic_matrix[:3]
    R = cv2.Rodrigues(r)[0]
	
    inverse = np.array([[1, 0, 0],
                        [0, -1, 0],
                        [0, 0, -1]])
	# 奇异值分解,消除标定误差导致的旋转矩阵不合格的情况。
    u, _, v = np.linalg.svd(R)
    R = u @ v
	
	# OpenGL相机坐标系下z轴负向为正方向
    rotation = inverse @ R
    translation = inverse @ t
    
    model_view_matrix = np.identity(4, dtype=np.float32)
    model_view_matrix[:3, :3] = rotation
    model_view_matrix[:3, 3] = translation
	
	# OpengGL中矩阵为列优先存储
    model_view_matrix = model_view_matrix.T
    return model_view_matrix

接下来是绘制背景图像,这个就很简单了。

def render_background_image(bg_model):
    glDisable(GL_DEPTH_TEST)
    bg_model.draw(bg_shader_program, draw_type=GL_TRIANGLES)
    glEnable(GL_DEPTH_TEST)

整个OpenGL视图分成两块,分别对应left和right。

def render():
    glClearColor(1.0, 1.0, 1.0, 0.0)
    glClearDepth(1.0)
    glPointSize(5)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glViewport(0, 0, int(SCR_WIDTH / 2), SCR_HEIGHT)
    render_background_image(bg_model_left)
    render_side_view(left_camera_intrinsic, left_camera_extrinsic, SCR_WIDTH / 2, SCR_HEIGHT, stereo_left_index)

    glViewport(int(SCR_WIDTH / 2), 0, int(SCR_WIDTH / 2), SCR_HEIGHT)
    render_background_image(bg_model_right)
    render_side_view(right_camera_intrinsic, right_camera_extrinsic, SCR_WIDTH / 2, SCR_HEIGHT, stereo_right_index)

最后就是效果图(不小心上镜了???)
在这里插入图片描述

<think>好的,我需要帮助用户在Ubuntu 18.04上找到标定双目相机内参的方法或教程。首先,我应该回忆一下相关的引用内容,看看有没有可用的信息。 用户提供的引用中有几个关于相机标定的例子,比如引用[2]提到使用kalibr标定工具进行相机标定,引用[3]使用camera_calibration包,引用[4]提到Astra深度相机标定问题。这些可能对用户的问题有帮助。 接下来,我需要确定双目相机内参标定的步骤通常包括哪些。一般来说,可能需要分别标定每个相机内参,然后标定它们之间的。但用户主要问的是内参,所以重点在单个相机标定。 引用[3]中的camercalibrator.py是ROS中的单目相机标定工具,用户可能需要先对左右相机分别进行内参标定。然后,如果需要双目之间的,可能需要其他工具,比如kalibr,如引用[2]提到的。 步骤可能包括:安装ROS环境,安装标定工具如camera_calibration和kalibr,使用棋盘格或标定板采集图像,分别运行单目标定,然后处理双目。此,需要注意相机驱动的正确安装,确保图像话题正确,如引用[3]中的/usb_cam/image_raw。 另,用户提到的Ubuntu 18.04可能对应ROS Melodic,需要确认工具是否兼容。例如,引用[4]提到在Melodic下预览图像有问题,但在rviz中正常,这可能需要注意图像传输插件是否正确安装,如引用[1]中的ros-melodic-image-transport-plugins。 总结步骤:安装依赖和工具,启动相机节点,运行单目标定节点分别处理左右相机,保存内参文件,可能需要后续的双目标定。同时,需要注意标定板的数设置,比如棋盘格大小和方格尺寸,如引用[3]中的--size 8x8 --square 0.025。 最后,可能需要提供具体的命令示例和注意事项,比如如何正确设置话题名称,避免常见的坑,如依赖项安装问题(引用[1]中的坑1)或图像显示问题(引用[4])。</think>在Ubuntu 18.04系统下进行双目相机内参标定,可通过以下步骤实现: --- ### 一、环境准备 1. **安装ROS Melodic** 需确保已正确安装ROS Melodic框架,这是运行相机标定工具的基础环境[^2][^4]。 2. **安装标定工具依赖** 执行以下命令安装关键依赖包: ```bash sudo apt-get install ros-melodic-camera-calibration ros-melodic-camera-calibration-parsers ros-melodic-kalibr ``` 3. **验证相机驱动** 确保双目相机驱动正常,例如Realsense相机需安装`realsense2_camera`包,并通过`rostopic list`确认图像话题存在[^2][^3]。 --- ### 二、单目相机内参标定 1. **启动相机节点** 例如使用Realsense相机: ```bash roslaunch realsense2_camera rs_camera.launch ``` 2. **运行标定程序** 对左目和右目相机分别标定。以左目为例: ```bash rosrun camera_calibration cameracalibrator.py \ --size 8x6 \ # 棋盘格角点数量(宽高减1) --square 0.024 \ # 每个方格边长(单位:米) image:=/camera/left/image_raw \ camera:=/camera/left ``` 右目同理,将话题名替换为右目对应的`/camera/right/image_raw`[^3]。 3. **采集数据与计算数** - 移动棋盘格至不同位置和角度,确保标定界面进度条填满 - 点击**CALIBRATE**,等待计算完成 - 保存生成的`ost.yaml`和`ost.txt`文件 --- ### 三、双目相机联合标定(可选) 若需标定双目间,可使用`kalibr`工具: ```bash kalibr_calibrate_cameras \ --target checkerboard.yaml \ # 标定数文件 --bag stereo_calibration.bag \ # 录制的双目图像数据包 --models pinhole-radtan pinhole-radtan \ --topics /camera/left/image_raw /camera/right/image_raw ``` 需提前录制双目同步图像数据包(考引用[2]方法)。 --- ### 四、注意事项 1. **标定板选择** 建议使用高精度打印的棋盘格,避免反光或变形。 2. **环境光照** 确保光照均匀,避免过曝或阴影干扰角点检测。 3. **常见问题** - 若图像显示异常,检查`libopencv-dev`和`ros-melodic-vision-opencv`是否安装[^1][^4] - 标定误差较大时,增加数据采集位置多样性 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值