相机内参

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

Zivid相机模型是专有的,这就是我们的内部相机内参无法通过SDK获取的原因。但是,我们提供了OpenCV和Halcon模型的近似值,因为许多机器视觉算法都依赖它们。

小心

一般来说,我们倾向于不鼓励使用相机内参。其中一个原因是在近似值中丢失了一些有价值的信息。另一个原因是通常有更好的方法可以达到相同的结果。由于主题的复杂性,我们建议您联络我们来讨论您的用例。内参是复杂的,建议尽可能使用点云!

OpenCV相机内参

Zivid SDK offers a few options to get OpenCV camera intrinsics.

intrinsics(camera)

Return intrinsics that corresponds to the default value of Zivid::Settings::Sampling::Pixel for the camera.

intrinsics(camera, settings)

Return intrinsics that corresponds to the value of Zivid::Settings::Sampling::Pixel used in settings.

intrinsics(camera, settings_2d)

Return intrinsics that corresponds to the capture with settings_2d.

estimateIntrinsics(frame)

Returns intrinsics that corresponds to the value of Zivid::Settings::Sampling::Pixel that was used to capture the frame.

针对固定光圈和固定温度给出的硬编码的相机内参。这个温度和光圈对应于我们认为的典型条件。

相机型号

镜头温度 (°C)

光圈

Zivid 2+

35

2.68

Zivid 2

35

2.30

Zivid One+

35

6.28

要获得硬编码的相机内参,您首先必须连接到相机:

跳转到源码

source

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

源码

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

source

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

Then, you can get the default OpenCV camera intrinsics (this function returns right away):

跳转到源码

source

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

源码

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

source

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

Alternatively, you can get the OpenCV camera intrinsics corresponding to the value of Zivid::Settings::Sampling::Pixel used in settings:

跳转到源码

source

const auto settingsSubsampled =
    Zivid::Settings{ Zivid::Settings::Experimental::Engine::phase,
                     Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} },
                     Zivid::Settings::Sampling::Pixel::blueSubsample2x2 };
const auto fixedIntrinsicsForSubsampledSettings =
    Zivid::Experimental::Calibration::intrinsics(camera, settingsSubsampled);
跳转到源码

source

var settingsSubsampled = new Zivid.NET.Settings();
settingsSubsampled.Acquisitions.Add(new Zivid.NET.Settings.Acquisition { });
settingsSubsampled.Sampling.Pixel = Zivid.NET.Settings.SamplingGroup.PixelOption.BlueSubsample2x2;
var fixedIntrinsicsForSubsampledSettings = Zivid.NET.Experimental.Calibration.Calibrator.Intrinsics(camera, settingsSubsampled);
跳转到源码

source

settings_subsampled = zivid.Settings(
    acquisitions=[zivid.Settings.Acquisition()],
    sampling=zivid.Settings.Sampling(pixel=zivid.Settings.Sampling.Pixel.blueSubsample2x2),
)
fixed_intrinsics_for_subsampled_settings = calibration.intrinsics(camera, settings_subsampled)

Or, similarly for 2D settings:

const auto settings2D = Zivid::Settings2D{ Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} }};
const auto fixedIntrinsicsForSettings2D = Zivid::Experimental::Calibration::intrinsics(camera, settings2D);
var settings2D = new Zivid.NET.Settings2D
{
   Acquisitions = { new Zivid.NET.Settings2D.Acquisition { } }
};
var fixedIntrinsicsForSettings2D = Zivid.NET.Experimental.Calibration.Intrinsics(camera, settings2D);
settings_2d = zivid.Settings2D()
fixed_intrinsics_for_settings_2d = calibration.intrinsics(camera, settings_2d)

小心

The hard-coded OpenCV intrinsics are fixed and does not adapt to the environment, unlike the calibration of our point clouds. Therefore, they will not correspond perfectly to a capture taken with a different aperture at a different temperature.

生产中的环境温度可能会发生变化,相机温度也会随之变化。热稳定有助于调节相机内部温度。然而,如果相机没有时间进行预热,那么在部署开始时镜头温度可能会比稳定期后低得多。由于温差,硬编码的内参与点云数据的一致性会较差。

当谈到光圈时,如果使用每次采集都设置了不同光圈的HDR模式捕获点云,情况会变得更加复杂。这是因为确定这种情况的内参并非易事。

由于这些复杂性,我们提供了一种获取OpenCV类型相机内参的替代方法:从点云估计的相机内参。

这些相机内参是从点云中估计出来的。Zivid标定下的点云是由包括温度和光圈数据的函数生成的。因此,估计的内参间接利用了温度和光圈数据。

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

跳转到源码

source

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

源码

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

source

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

然后您必须捕获一幅图像:

跳转到源码

源码

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

源码

var frame = camera.Capture(settings);
跳转到源码

源码

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

然后,您可以从frame估计内参(因为涉及计算,此函数不会立即返回):

跳转到源码

source

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

源码

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

source

estimated_intrinsics = calibration.estimate_intrinsics(frame)

Note that if you set Zivid::Settings::Sampling::Pixel to e.g. Zivid::Settings::Sampling::Pixel::blueSubsample2x2, then you get correct (subsampled) intrinsics with the same function:

跳转到源码

source

const auto settingsSubsampled =
    Zivid::Settings{ Zivid::Settings::Experimental::Engine::phase,
                     Zivid::Settings::Acquisitions{ Zivid::Settings::Acquisition{} },
                     Zivid::Settings::Sampling::Pixel::blueSubsample2x2 };
const auto frame = camera.capture(settingsSubsampled);
const auto estimatedIntrinsicsForSubsampledSettings =
    Zivid::Experimental::Calibration::estimateIntrinsics(frame);
跳转到源码

source

var settingsSubsampled = new Zivid.NET.Settings();
settingsSubsampled.Acquisitions.Add(new Zivid.NET.Settings.Acquisition { });
settingsSubsampled.Sampling.Pixel = Zivid.NET.Settings.SamplingGroup.PixelOption.BlueSubsample2x2;
var frame = camera.Capture(settingsSubsampled);
var estimatedIntrinsicsForSubsampledSettings = Zivid.NET.Experimental.Calibration.Calibrator.EstimateIntrinsics(frame);
跳转到源码

source

settings_subsampled = zivid.Settings(
    acquisitions=[zivid.Settings.Acquisition()],
    sampling=zivid.Settings.Sampling(pixel=zivid.Settings.Sampling.Pixel.blueSubsample2x2),
)
frame = camera.capture(settings_subsampled)
estimated_intrinsics_for_subsampled_settings = calibration.estimate_intrinsics(frame)

保存相机内参

可以将OpenCV相机内参保存到YML文件中:

跳转到源码

source

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

源码

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*。

备注

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

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

硬编码相机内参

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

  • 您可以从以下任一方式获得彩色图像:

    • 2D捕获

    • 单次采集3D捕获

    • Color Mode 设置为 UseFirstAcquisition 的多次采集HDR 3D捕获。

  • 对于您的相关采集(上述三个选项之一),您可以使用我们提供硬编码内参的光圈值(参见 )。

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

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

通过点云估计相机内参

我们建议在以下情况使用估计的内参:

  • 您从多次采集HDR 3D捕获中获取彩色图像,且 Color Mode 被设置为 AutomaticToneMapping 。这是因为点云很可能是使用不同光圈和在不同于对应硬编码内参的温度下进行采集的结果。

  • 存在必须使用OpenCV内参的任何其他用例时,例如:

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

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

备注

The estimated camera intrinsics also work well for all cases where we recommend the hard-coded camera intrinsics. Therefore, for simplicity, you could always use the estimateIntrinsics function. However, estimating intrinsics from the point cloud takes time, whereas getting the hard-coded intrinsics from the camera is instantaneous.

In addition, the estimated intrinsics uses 3D capture settings. This means that the intrinsics corresponds to the 3D resolution. If you take a separate 2D capture where the resolution is different from 3D then you will get incorrect intrinsics. In this case use the hard-coded method.

2D and 3D capture with different resolution

You will require different intrinsics based on the resolution of your 2D image. When you perform a Monochrome Capture you may get different resolution in 2D and 3D. If you take the 2D data from a 3D capture then estimateIntrinsics will return the intrinsics you want. If you get 2D data from a separate 2D capture, then you can call intrinsics(camera, settings_2d), where settings_2d are the settings used for the 2D capture.

备注

estimateIntrinsics provides the best intrinsics. Thus, even when you capture separate 2D we recommend to use these intrinsics. If the 2D resolution is different however you will have to modify the intrinsics accordingly. In this case please contact us at customersuccess@zivid.com.

Instead of creating intrinsics to match the resolution in 2D you may downsample or subsample the 2D image to match the 3D resolution.

手眼标定

一般来说,我们推荐的手眼标定是Zivid 手眼标定 ,因为它最适合Zivid相机。我们的手眼标定方法不需要相机内参,但是许多其它方法需要内参。如果您使用这些方法中的某一种,我们建议使用从点云估计的相机内参。阅读有关 选择正确的手眼标定方法 了解更多信息。

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

在将Zivid点云投影到2D图像平面时,使用估计的内参将获得比使用硬编码内参更小的重新投影误差。但是请记住,如果使用我们的校正过滤器,比如 Gaussian Smoothing(高斯平滑)Contrast Distortion Filter(对比度失真过滤器) ,那么将导致更大的重新投影误差。当在没有使用校正过滤器的情况下捕获的点云上使用估计的内参时,预计的重新投影误差小于1个像素。当使用了校正过滤器时,对于显着校正的点,重新投影误差会更大。然而,对于大多数点,应该仅有小于1个像素的重新投影误差。

备注

Downsampled or Subsampled 2D

When you subsample the 2D data you get direct 1-to-1 mapping between 2D and 3D from Monochrome Capture.

Now consider downsampling a full-resolution 2D image. It is important to understand which pixels are used to generate the downsampled pixels. If you use pixels symmetrically around the wanted pixel, then the averaged pixel should land on the pixel location that corresponds to the 3D data. This corresponds best with intrinsics that the SDK provides.

For more information see 2D.

从2D图像估计3D位姿

假设您正在根据2D图像估计对象的3D位姿,例如,使用OpenCV中的solvePnP()。与硬编码相机内参相比,从点云估计的内参将提供更好的结果。但是,我们不建议从2D图像中估计位姿,因为可以直接从点云中更准确地估计位姿。

2D图像处理算法

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

Version History

SDK

Changes

2.10.0

Monochrome Capture requires modifications to the intrinsics before using them.