相机内参

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(重采样)

或者,如果没有进行重采样,您可以使用 pixelMapping(camera, settings) 函数来获取 3D 和全分辨率 2D 中任何采样配置的正确点到像素映射。

小心

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

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

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

我们建议直接使用点云数据和 像素映射 而不是内参。

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

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 设置为 disiabled ,则会得到正确的(子采样后的)内内参:

跳转到源码

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);
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 采集中获取点云

  • 对于与硬编码光圈类似的光圈(用于 2D 和 3D)(参见 )。

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

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

通过点云估计相机内参

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

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

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

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

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

备注

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

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

我们建议使用 像素映射 和点云数据来使用 2D 和 3D 数据。这样可以正确处理分辨率差异。

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

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

手眼标定

我们推荐Zivid的 手眼标定 标定,因为它最适合 Zivid 相机。我们的手眼标定方法不需要使用相机内参;但是许多其他方法都需要。如果您使用其他方法之一,我们建议使用通过点云 estimateIntrinsics() 。阅读有关 选择正确的手眼标定方法 的更多信息。

将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(单色捕获) 需要在使用它们之前修改内参。