基于棋盘格的坐标转换

本教程展示了如何估计棋盘格的位姿并使用4x4齐次变换矩阵将点云转换到棋盘格坐标系。此示例还使用了转换矩阵来保存YAML文件。

小技巧

如果您使用的是Zivid One+ Small相机,则棋盘格对于此应用程序可能太大了。对于这种情况,我们有一个 基于ArUco标记的坐标转换 教程。

本教程使用下图中显示的棋盘格的点云。

标定板2D图像

我们可以在Zivid Studio中打开 原始点云 并进行检查。

备注

原始点云在 Sample Data(示例数据) 中。

现在,我们可以将深度视图中的Z范围设置为540毫米至735毫米。这使我们可以看到相机和棋盘格坐标系之间存在一个角度。

相机坐标系中的标定板

首先,我们加载一个棋盘格的点云。

跳转到源

源码

const auto calibrationBoardFile = std::string(ZIVID_SAMPLE_DATA_DIR) + "/CalibrationBoardInCameraOrigin.zdf";
std::cout << "Reading ZDF frame from file: " << calibrationBoardFile << std::endl;
const auto frame = Zivid::Frame(calibrationBoardFile);
auto pointCloud = frame.pointCloud();
跳转到源

源码

var calibrationBoardFile = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
               + "/Zivid/CalibrationBoardInCameraOrigin.zdf";
Console.WriteLine("Reading ZDF frame from file: " + calibrationBoardFile);
var frame = new Zivid.NET.Frame(calibrationBoardFile);
var pointCloud = frame.PointCloud;

然后我们需要估计棋盘格的位姿。

跳转到源

source

std::cout << "Detecting and estimating pose of the Zivid checkerboard in the camera frame" << std::endl;
const auto detectionResult = Zivid::Calibration::detectFeaturePoints(frame.pointCloud());
const auto transformCameraToCheckerboard = detectionResult.pose().toMatrix();
std::cout << transformCameraToCheckerboard << std::endl;
跳转到源

source

Console.WriteLine("Detecting and estimating pose of the Zivid checkerboard in the camera frame");
var detectionResult = Detector.DetectFeaturePoints(pointCloud);
var transformCameraToCheckerboard = new Zivid.NET.Matrix4x4(detectionResult.Pose().ToMatrix());
Console.WriteLine(transformCameraToCheckerboard);

在转换点云之前,我们将变换矩阵求逆,以便得到相机在棋盘格坐标系中的位姿。

跳转到源

source

std::cout << "Camera pose in checkerboard frame:" << std::endl;
const auto transformCheckerboardToCamera = transformCameraToCheckerboard.inverse();
std::cout << transformCheckerboardToCamera << std::endl;
跳转到源

source

Console.WriteLine("Camera pose in checkerboard frame:");
var transformCheckerboardToCamera = transformCameraToCheckerboard.Inverse();
Console.WriteLine(transformCheckerboardToCamera);

转换后,我们将位姿保存到YAML文件中。

跳转到源

source

const auto transformFile = "CheckerboardToCameraTransform.yaml";
std::cout << "Saving a YAML file with Inverted checkerboard pose to file: " << transformFile << std::endl;
transformCheckerboardToCamera.save(transformFile);

这是YAML文件的内容:

__version__:
  serializer: 1
  data: 1
FloatMatrix:
  Data: [
    [9.79164362e-01, 4.36628871e-02, 1.98319763e-01, 1.77465611e+01],
    [5.02591990e-02, 8.94120097e-01, -4.44997996e-01, 4.31194275e+02],
    [-1.96751565e-01, 4.45693552e-01, 8.73296201e-01, -5.47788330e+02],
    [0, 0, 0, 1]]

之后,我们将点云转换到棋盘格坐标系。

跳转到源

source

std::cout << "Transforming point cloud from camera frame to Checkerboard frame" << std::endl;
pointCloud.transform(transformCheckerboardToCamera);
跳转到源

source

Console.WriteLine("Transforming point cloud from camera frame to Checkerboard frame");
pointCloud.Transform(transformCheckerboardToCamera);

提示

了解更多关于 位置、方向和坐标变换

在保存转换后的点云之前,我们将其转换为OpenCV 2D图像格式并绘制坐标系及显示出来。

跳转到源

source

std::cout << "Converting to OpenCV image format" << std::endl;
const auto bgrImage = pointCloudToColorBGR(pointCloud);
std::cout << "Visualizing checkerboard with coordinate system" << std::endl;
drawCoordinateSystem(frame, transformCameraToCheckerboard, bgrImage);
displayBGR(bgrImage, "Checkerboard transformation frame");

在这里我们可以看到将要显示的图像,我们可以观察到棋盘格的坐标系在哪里。

棋盘格坐标系

最后,我们将转换后的点云保存到磁盘。

跳转到源

source

const auto checkerboardTransformedFile = "CalibrationBoardInCheckerboardOrigin.zdf";
std::cout << "Saving transformed point cloud to file: " << checkerboardTransformedFile << std::endl;
frame.save(checkerboardTransformedFile);
跳转到源

source

var checkerboardTransformedFile = "CalibrationBoardInCheckerboardOrigin.zdf";
Console.WriteLine("Saving transformed point cloud to file: " + checkerboardTransformedFile);
frame.Save(checkerboardTransformedFile);

现在我们可以在Zivid Studio中打开 转换后的点云 并进行检查。

备注

在Zivid Studio中缩小图像来查找数据,因为视点原点不适用于转换后的点云。

我们现在可以在深度视图中手动将Z范围设置为-35mm至1mm,这样我们就可以过滤掉除了标定板和它旁边的物体之外的所有数据。这使我们可以看到我们在标定板上具有相同的Z值,并且从颜色渐变中我们可以检查该值是否为0。这意味着点云的原点位于棋盘格上。

在棋盘格坐标系中的标定板