相机内参

Zivid相机模型比一些广为人知的针孔相机模型(例如OpenCV相机模型)更复杂,使用了更多的内参。此外,我们的相机使用了一种滚动校准技术,这意味着点云是作为光圈、温度和颜色通道的函数生成的。

Zivid 相机中的 3D 到 2D 映射

每个相机在空间中的 3D 点与其对应的 2D 像素索引之间都有物理关系。对于 Zivid 相机:

  • 相同分辨率:当 2D 和 3D 数据具有相同的分辨率时,两者之间存在直接的 1:1 映射。

  • 不同的分辨率:如果 2D 和 3D 分辨率不同,则映射取决于以下设置:

    • Settings2D::Sampling::Pixel

    • Zivid::Settings::Sampling::Pixel

为了在 2D 和 3D 数据之间保持 1:1 的对应关系,您可以使用 Settings::Processing::Resampling 设置对 3D 点云进行重新采样。有关更多信息,请参阅 Resampling(重采样)

Alternatively, if resampling is not performed, you can use the pixelMapping(camera, settings) function to get correct point-to-pixel mapping for any combination of 2D and 3D settings.

小心

由于以下原因,我们建议不要使用相机内参:

  • 信息丢失:近似值可能会导致有价值信息的丢失。

  • 更好的替代方案:通常可以采用更有效的方法来获得类似或更好的结果。

We recommend using the point cloud data directly and pixel mapping instead of intrinsics.

Zivid 相机模型是专有的,这就是为什么我们的内部相机的内参在 SDK 中不可用。但是,由于许多机器视觉算法依赖于标准模型,Zivid 提供了 OpenCV 和 Halcon 内在函数模型的近似值以实现兼容性。

OpenCV相机内参

Zivid SDK 提供了一些获取 OpenCV 相机内参的方法。

函数名称

返回的内参对应的分辨率

intrinsics(camera)

相机的 Zivid::Settings::Sampling::Pixel 的默认值

intrinsics(camera, settings)

Zivid::Settings::Sampling::PixelZivid::Settings::Resamplingsettings 的组合

intrinsics(camera, settings_2d)

Zivid::Settings2D::Sampling::Pixelsettings_2d 的值

estimateIntrinsics(frame)

用于捕获 frameZivid::Settings::Sampling::PixelZivid::Settings::Resampling 的组合

我们建议从点云中估算内参以获得最准确的结果。硬编码相机内参是根据特定的光圈和温度给出的。因此,它不会像估计的内参那样准确。请参阅下面的列表以了解每个相机型号的数值。

相机型号

镜头温度 (°C)

光圈

Zivid 2+

35

2.68

Zivid 2

35

2.30

相机内参是根据点云估算出来的,同时考虑到了拍摄过程中使用的光圈和温度。

要获得估计的OpenCV内参,您首先必须连接到相机:

跳转到源码

source

std::cout << "Connecting to camera" << std::endl;
auto camera = zivid.connectCamera();
跳转到源码

source

Console.WriteLine("Connecting to camera");
var camera = zivid.ConnectCamera();
跳转到源码

源码

print("Connecting to camera")
camera = app.connect_camera()

调用捕获函数获取 frame:

跳转到源码

source

const auto frame = camera.capture2D3D(settings);
跳转到源码

source

using (var frame = camera.Capture2D3D(settings))
{
跳转到源码

source

with camera.capture_2d_3d(settings=settings) as frame:

然后,您可以从 frame 中获取估算的内参:

跳转到源码

source

const auto estimated_intrinsics = Zivid::Experimental::Calibration::estimateIntrinsics(frame);
跳转到源码

source

var estimatedIntrinsics = Zivid.NET.Experimental.Calibration.Calibrator.EstimateIntrinsics(frame);
跳转到源码

source

estimated_intrinsics = zivid.experimental.calibration.estimate_intrinsics(frame)

估算内参的函数考虑了采样策略。例如,如果将 Zivid::Settings::Sampling::Pixel 设置为 by2x2 并将 Zivid::Settings::Resampling 设置为 disabled ,则会得到正确的(子采样后的)内内参:

跳转到源码

source

const auto settingsSubsampled = subsampledSettingsForCamera(camera);
const auto frame = camera.capture2D3D(settingsSubsampled);
const auto estimatedIntrinsicsForSubsampledSettings =
    Zivid::Experimental::Calibration::estimateIntrinsics(frame);
跳转到源码

source

var settingsSubsampled = SubsampledSettingsForCamera(camera);
using (var frameSubsampled = camera.Capture2D3D(settingsSubsampled))
{
    var estimatedIntrinsicsForSubsampledSettings = Zivid.NET.Experimental.Calibration.Calibrator.EstimateIntrinsics(frameSubsampled);
跳转到源码

source

settings_subsampled = _subsampled_settings_for_camera(camera)
frame = camera.capture_2d_3d(settings_subsampled)
estimated_intrinsics_for_subsampled_settings = zivid.experimental.calibration.estimate_intrinsics(frame)

硬编码内参是根据特定光圈和温度给出的。如需获取硬编码相机内参,请先连接到相机:

跳转到源码

source

std::cout << "Connecting to camera" << std::endl;
auto camera = zivid.connectCamera();
跳转到源码

source

Console.WriteLine("Connecting to camera");
var camera = zivid.ConnectCamera();
跳转到源码

源码

print("Connecting to camera")
camera = app.connect_camera()

然后,您可以获取默认的 OpenCV 格式的相机内参:

跳转到源码

source

std::cout << "Getting camera intrinsics" << std::endl;
const auto intrinsics = Zivid::Experimental::Calibration::intrinsics(camera);
跳转到源码

source

Console.WriteLine("Getting camera intrinsics");
var intrinsics = Zivid.NET.Experimental.Calibration.Calibrator.Intrinsics(camera);
跳转到源码

source

print("Getting camera intrinsics")
intrinsics = zivid.experimental.calibration.intrinsics(camera)

如果您使用了采样功能,则可以获取与 settings 中的 Zivid::Settings::Sampling::PixelZivid::Settings::Resampling 的组合相所对应的 OpenCV 相机内参:

跳转到源码

source

const auto settingsSubsampled = subsampledSettingsForCamera(camera);
const auto fixedIntrinsicsForSubsampledSettings =
    Zivid::Experimental::Calibration::intrinsics(camera, settingsSubsampled);
跳转到源码

source

var settingsSubsampled = SubsampledSettingsForCamera(camera);
var fixedIntrinsicsForSubsampledSettings = Zivid.NET.Experimental.Calibration.Calibrator.Intrinsics(camera, settingsSubsampled);
跳转到源码

source

settings_subsampled = _subsampled_settings_for_camera(camera)
fixed_intrinsics_for_subsampled_settings = zivid.experimental.calibration.intrinsics(camera, settings_subsampled)

使用 2D 设置采集时的硬编码内参:

跳转到源码

source

const auto settings2D =
    Zivid::Settings2D{ Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } };
const auto fixedIntrinsicsForSettings2D = Zivid::Experimental::Calibration::intrinsics(camera, settings2D);
跳转到源码

source

var settings2D = new Zivid.NET.Settings2D
{
    Acquisitions = { new Zivid.NET.Settings2D.Acquisition { } }
};
var fixedIntrinsicsForSettings2D = Zivid.NET.Experimental.Calibration.Calibrator.Intrinsics(camera, settings2D);
跳转到源码

source

settings_2d = zivid.Settings2D()
settings_2d.acquisitions.append(zivid.Settings2D.Acquisition())
fixed_intrinsics_for_settings_2d = zivid.experimental.calibration.intrinsics(camera, settings_2d)

小心

硬编码的 OpenCV 内参是固定的,与 estimateIntrinsics 不同,它无法适应温度或光圈的变化。这意味着它们可能与在不同条件下拍摄的图像不匹配。

环境温度变化会影响相机的内部温度。虽然热稳定对此有所帮助,但镜头温度在部署开始和稳定后仍然会有很大差异。这种温差可能会导致硬编码内参和点云数据之间出现差异。光圈变化,特别是在 HDR 模式下,每次采集使用不同的光圈时,会进一步使硬编码内参的准确性复杂化。

由于这些复杂性,我们建议从点云估算相机内参以获得更准确的结果。

保存相机内参

您可以使用以下代码将 OpenCV 相机内参保存到 YML 文件:

跳转到源码

source

const auto outputFile = "Intrinsics.yml";
std::cout << "Saving camera intrinsics to file: " << outputFile << std::endl;
intrinsics.save(outputFile);
跳转到源码

source

var intrinsicsFile = "Intrinsics.yml";
Console.WriteLine("Saving camera intrinsics to file: " + intrinsicsFile);
intrinsics.Save(intrinsicsFile);
跳转到源码

source

output_file = "Intrinsics.yml"
print(f"Saving camera intrinsics to file: {output_file}")
intrinsics.save(output_file)

Halcon相机内参

Halcon使用的是不同于Zivid和OpenCV的相机模型。有两种方法可以获得Halcon内参,两者都基于OpenCV模型的近似值。

小心

如果您需要使用 Halcon 格式的内参(相机内部参数),请使用下面描述的方法之一来获取它们。请勿在 Halcon 中校准我们的 2D 相机以获取 Halcon 内参;它无法很好地与我们的相机配合使用。

要求:

  • 安装了Python和具备运行Python脚本的技能

  • 安装了 Zivid-Python

为您的相机获取Halcon内参的最简单方法是运行 convert_intrinsics_opencv_to_halcon.py 代码示例。阅读示例描述,重点关注 example when reading from camera

备注

此方法仅限于获取硬编码的相机内参。

要求:

  • 安装了Python和具备运行Python脚本的技能

  • 构建C++或C#代码示例的技能

为您的相机获取Halcon内参的另一种方法是从YML文件加载OpenCV相机内参并将它们转换为Halcon格式。

要获取OpenCV相机内参并将它们保存到文件中,请运行以下示例之一:

要获取OpenCV相机内参并将它们保存到文件中,请运行 GetCameraIntrinsics.cpp 。查看 使用 CMake 配置 C++ 示例并在 Windows 的 Visual Studio 中构建它们

要获取OpenCV相机内参并将它们保存到文件中,请运行 GetCameraIntrinsics.cs 。查看 使用Visual Studio构建C#示例 构建C#示例。

要获取OpenCV相机内参并将它们保存到文件中,请运行 get_camera_intrinsics.py

然后,运行 convert_intrinsics_opencv_to_halcon.py 代码示例。阅读示例描述,重点关注*Example when reading from file*。

备注

这种方法允许获得硬编码的相机内参和从点云估计的相机内参。但是对于后面一种方式,您需要保存和加载您需要的内参的每一次捕获。

我应该使用哪种相机内参?

一般来说,我们建议使用实际点云数据和 pixelMapping(camera, settings) 函数而不是内参。如果绝对必要,请参阅以下指南以选择正确的相机内部函数。

硬编码相机内参

我们建议仅在以下情况下使用硬编码相机内参:

  • 有下列情形之一的,

    • 使用 capture2D() 从 2D 采集获取彩色图像

    • 使用 capture2D() 从 2D 采集中获取彩色图像,并使用 capture3D() 从 3D 采集中获取点云

    • 使用 capture2D3D() 从 3D 采集中获取点云

  • For apertures (used for both 2D and 3D) similar to the hard-coded one (see the table).

  • 接近*室内*温度的环境温度。

  • 仅使用2D数据的应用,例如,使图像不失真以检测直线。

通过点云估计相机内参

我们建议在几乎所有情况下都使用估算的内参:

  • 不论您是如何获得彩色图像和点云的。这是因为点云可能是使用不同光圈和不同温度(与硬编码内参对应的温度不同)采集的结果。

  • 使用 OpenCV 格式的内参时的任何用例都是必要的,例如:

    • 使用 projectPoints() 将3D数据投影到2D图像。

    • 使用 solvePnP() 从 2D 图像估计 3D 位姿。

备注

在我们推荐使用硬编码内参的所有情况下,估算的相机内参也能使用。但是,估算内参需要一些计算时间,而从相机获取硬编码内参则是即时的。

不同分辨率的 2D 和 3D 捕获

We recommend using pixel mapping and the point cloud data to go from 2D to 3D. This will handle the resolution difference correctly.

另一种方法是通过对 2D 图像进行下采样或子采样以匹配 3D 分辨率,从而使 2D 数据的分辨率与 3D 数据相匹配。如需了解更多信息,请参阅 Sampling(采样) - 3DSampling(采样)- 2DResampling(重采样)

如果您仍然需要使用内参,我们建议使用 estimateIntrinsics(frame)

手眼标定

We recommend our own 手眼标定 calibration, as it is best suited for Zivid cameras. Our hand-eye calibration method does not require camera intrinsics; however, many other methods do. If you use one of the other methods, we recommend using estimateIntrinsics() from the point cloud. Read more about choosing the correct Hand-Eye calibration method.

将3D点投影到2D图像平面

我们建议在将 Zivid 点云投影到 2D 图像平面时使用 estimateIntrinsics

这将导致比使用硬编码内参更小的重新投影误差。但是,请记住,如果使用了我们的校正过滤器,例如 Gaussian Smoothing(高斯平滑)Contrast Distortion Filter(对比度失真过滤器) ,将会增加重新投影的误差。在没有使用校正过滤器捕获的点云上使用估算的内参时,预期的重新投影误差小于 1 个像素。当使用了校正过滤器时,对于显著校正的点,重新投影误差会更大。但是,对于大多数点,重新投影误差应该小于 1 个像素。

降采样或子采样 2D

当您对 2D 数据进行子采样/降采样时,您可以重新获得 2D 和 3D 之间的直接 1 对 1 映射,请参阅 Sampling(采样) - 3D

在对全分辨率 2D 图像进行降采样时,了解哪些像素用于生成降采样像素是非常重要的。如果您在所需像素周围对称地使用像素,则平均像素应落在与 3D 数据相对应的像素位置上。这与 SDK 提供的内参最相符。

更多信息请参阅:

从2D图像估计3D位姿

将二维像素投影到三维空间时,我们建议使用点云中的 estimateIntrinsics

与硬编码的相机固定内参相比,从点云估计的内参将提供更好的结果。然而,我们更建议直接从点云估计位姿,因为这样会更准确。

2D图像处理算法

如果您的应用只使用2D数据,那么硬编码的内参和从点云估计的内参都可以正常工作。一个例子是校正2D图像的失真来校正镜头失真,从而保证直线的检测。

版本历史

SDK

变更

2.10.0

Monochrome Capture(单色捕获) 需要在使用它们之前修改内参。