多相机标定教程

本教程介绍了如何使用 Zivid SDK 对多台相机进行相互校准。标定结果是一个从每台相机到主相机的变换矩阵。主相机默认为第一台被连接的相机,但您可以通过其序列号轻松控制它。

先决条件

您应该已经安装了 Zivid SDK 和 C++ 示例。更多详细信息,请参阅 zivid-cpp-sampleszivid-python-samples 。本教程不会详细介绍 SDK 的基础知识,例如初始化和捕获。请参阅 捕获教程

连接到相机

在本教程中,我们将连接所有可用的相机。我们可以通过以下方式连接:

转至源代码

源码

auto cameras = zivid.cameras();
std::cout << "Number of cameras found: " << cameras.size() << std::endl;

auto connectedCameras = connectToAllAvailableCameras(cameras);
if(connectedCameras.size() < 2)
{
    throw std::runtime_error("At least two cameras need to be connected");
}
std::cout << "Number of connected cameras: " << connectedCameras.size() << std::endl;
转至源代码

源码

cameras = app.cameras()
print(f"Number of cameras found: {len(cameras)}")

connected_cameras = connect_to_all_available_cameras(cameras)
if len(connected_cameras) < 2:
    raise RuntimeError("At least two cameras need to be connected")
print(f"Number of connected cameras: {len(connected_cameras)}")

捕获标定对象

我们现在准备捕获标定对象。

示例中的捕获是使用特殊的标定板捕获功能进行的。

转至源代码

源码

const auto frame = Zivid::Calibration::captureCalibrationBoard(camera);
转至源代码

源码

frame = zivid.calibration.capture_calibration_board(camera)

当我们从文件加载点云时,我们只需将这行代码替换为:

转至源代码

源码

const auto frame = Zivid::Frame(fileName);
转至源代码

源码

frame = zivid.Frame(file_name)

检测棋盘格特征点

本教程中使用的标定对象是棋盘格。在进行标定之前,我们必须通过所有相机来检测棋盘格上的特征点。

转至源代码

源码

const auto detectionResult = Zivid::Calibration::detectCalibrationBoard(frame);
转至源代码

源码

detection_result = zivid.calibration.detect_calibration_board(frame)

此时,我们可以验证捕获的图像质量是否足够好。 detectionResult 是一种可以直接测试的类型。它重载了 bool 运算符来提供此信息。当质量测试通过后,我们会保存检测结果以及所用相机的序列号。

转至源代码

源码

if(detectionResult)
{
    Detection currentDetection(serial, detectionResult);
    detectionsList.push_back(currentDetection);
}
else
{
    throw std::runtime_error(
        "Could not detect checkerboard. Please ensure it is visible from all cameras.");
}
转至源代码

源码

if detection_result:
    detections_list.append(Detection(serial, detection_result))
else:
    raise RuntimeError("Could not detect checkerboard. Please ensure it is visible from all cameras.")

执行多相机标定

现在我们已经检测到所有相机的所有捕获中的所有特征点,之后我们可以执行多相机标定。

转至源代码

源码

const auto results = Zivid::Calibration::calibrateMultiCamera(detectionResultsList);
转至源代码

源码

results = zivid.calibration.calibrate_multi_camera(detection_results_list)

返回的 results 可以直接用于判断标定是否成功。同样,该类型重载了 bool 运算符。

转至源代码

源码

if(results)
{
    std::cout << "Multi-camera calibration OK." << std::endl;
}
else
{
    std::cout << "Multi-camera calibration FAILED." << std::endl;
}
转至源代码

源码

if results:
    print("Multi-camera calibration OK.")
else:
    print("Multi-camera calibration FAILED.")

results 包含两个向量:

  1. transforms - 包含所有变换矩阵

  2. residuals ——包含标定误差的数据

转至源代码

源码

const auto &transforms = results.transforms();
const auto &residuals = results.residuals();
转至源代码

源码

transforms = results.transforms()
residuals = results.residuals()

将转换矩阵保存为 YAML 文件

稍后我们会使用到标定结果,因此我们需要将转换结果存储在 YAML 文件中。为此,我们使用了我们的 API。跟踪哪个转换矩阵属于哪个相机非常重要。更准确地说,是跟踪标定过程中相机的位姿。因此,我们使用相机的序列号作为标识符,并将其用于文件名。

转至源代码

源码

transforms[i].save(transformationMatricesSavePath + "/" + detectionsList[i].serialNumber + ".yaml");
转至源代码

源码

assert_affine_matrix_and_save(
    transform, transformation_matrices_save_path / f"{detections_list[i].serial_number}.yaml"
)

结论

本篇教程展示了如何使用 Zivid SDK 进行多相机标定。您现在可以使用转换矩阵来拼接不同相机捕获的点云了。 请查看 转换拼接教程