跳转到内容
STAGING SERVER
DEVELOPMENT SERVER

处理测量结果#

本主题为您介绍如何处理 Basler blaze 和 Smart blaze 相机的测量结果。

信息

本主题中的所有信息均适用于所有 blaze 和 Smart blaze 相机型号。为简便起见,下文统一使用“blaze”指代所有型号。

概述#

Basler blaze 相机测量每个传感器像素的光传播距离。

使用这些距离,相机会在右旋坐标系中计算每个传感器像素的 x、y、z 坐标。坐标系的原点位于相机的光学中心,该中心位于相机外壳内。y 轴指向下方,z 轴指向远离相机的方向。

相机以深度图或点云的形式提供 3D 信息,取决于像素格式。在深度图中,z 坐标被编码为 16 位灰度值。如下所示,可以从灰度值中计算出所有 3D 坐标值。点云以浮点数的形式包含每个传感器像素的 x、y、z 3D 坐标。单位是 mm。

如果传感器像素没有有效的深度信息(例如由于 异常值剔除 或光照不足,即光线强度不足以通过 置信阈值),深度图或点云中的相应值将被设置为由 Scan3dInvalidDataValue 参数定义的值(默认设置为 0)。

处理深度图#

深度图由 16 位灰度值组成。对于每个传感器像素,相机会将 z 坐标值转换为灰度值,并将其存储在深度图中。

结合由 Scan3dCoordinateScale, Scan3dPrincipalPointU, Scan3dPrincipalPointV和 Scan3dFocalLength 参数提供的相机标定数据,可以从深度图中获取完整的 3D 信息。

信息

即: Scan3dCoordinateScale 参数值会因所选的 Pixel Format 而异。在 blaze Viewer 中使用相机时,Pixel Format 始终设置为 Coord3D_ABC32f Pixel Format。您无法更改此设置。blaze Viewer 提供的深度图是根据点云创建的。在此情况下, Scan3dCoordinateScale 参数值为 1。当您在 pylon Viewer 外部使用 blaze 相机并将 Pixel Format 设置为 Coord3D_C16, Scan3dCoordinateScale 参数值则不同。不同 Pixel Format 的 Scan3dCoordinateScale 参数值如下表所示。

Pixel Format Scan3dCoordinateScale[C] 参数值
Coord3D_ABC32f 1
Coord3D_C16 0.152588
Mono16 0.152588

请参阅 GrabDepthMap C++ 示例,了解如何配置相机以发送深度图以及如何访问深度图数据。

从 2D 深度图计算 3D 坐标#

要将深度图的 16 位灰度值转换为以 mm 为单位的 z 坐标,请使用以下公式:

z [mm] = gray2mm * g

其中:

g = 来自深度图的灰度值

gray2mm = 以下参数的值: Scan3dCoordinateScale 参数

要计算 x 和 y 坐标,请使用以下公式:

x [mm] = (u-cx) * z / f

y [mm] = (v-cy) * z / f

其中:

(u,v) = 深度图中的列与行

f = 以下参数的值: Scan3dFocalLength 参数,即相机镜头的焦距

(cx,cy) = 以下参数的值: Scan3dPrincipalPointU 和 Scan3dPrincipalPointV 参数,即主点

C++ 示例代码#

    // Enable depth maps by enabling the Range component and setting the appropriate pixel format.
    camera.ComponentSelector.SetValue(ComponentSelector_Range);
    camera.ComponentEnable.SetValue(true);
    camera.PixelFormat.SetValue(PixelFormat_Coord3D_C16);

    // Query the conversion factor required to convert gray values to distances:
    // Choose the z axis first...
    camera.Scan3dCoordinateSelector.SetValue(Scan3dCoordinateSelector_CoordinateC);
    // ... then retrieve the conversion factor.
    const auto gray2mm = camera.Scan3dCoordinateScale.GetValue();

    // Configure the gray value used for indicating missing depth data.
    // Note: Before setting the value, the Scan3dCoordinateSelector parameter must be set to the axis the
    // value is to be configured for, in this case the z axis. This means that Scan3dCoordianteSelector must be set
    // to "CoordinateC". This has already been done a few lines above.
    camera.Scan3dInvalidDataValue.SetValue((double)missingDepth);

    // Retrieve calibration data from the camera.
    const auto cx = camera.Scan3dPrincipalPointU.GetValue();
    const auto cy = camera.Scan3dPrincipalPointV.GetValue();
    const auto f = camera.Scan3dFocalLength.GetValue();

    // ....

    // Access the data.
    const auto container = ptrGrabResult->GetDataContainer();
    const auto rangeComponent = container.GetDataComponent(0);
    const auto width = rangeComponent.GetWidth();
    const auto height = rangeComponent.GetHeight();

    // Calculate coordinates for pixel (u,v).
    const uint16_t g = ((uint16_t*)rangeComponent.GetData())[u + v * width];
    const double z = g * gray2mm;
    const double x = (u - cx) * z / f;
    const double y = (v - cy) * z / f;

处理已保存的深度图#

对于使用 blaze 旧版 SDK、pylon SDK 或 blaze ROS 驱动程序获得的深度图,您必须使用以下公式:

测量距离 [mm] = Pixel_Value x Scan3dCoordinateScale[C]

对于使用 blaze Viewer 保存的深度图,请使用以下公式:

测量距离 [mm] = DepthMin_parameter + (Pixel_Value x (DepthMax_Parameter - DepthMin_parameter)) / 65535

处理点云#

由于点云由相机坐标系内的 x、y、z 坐标三元组组成,因此无需进一步处理即可从点云中提取 3D 信息。

有关如何配置用于发送点云的相机以及如何访问数据的信息,请参阅 FirstSample C++ 示例。

如果除了点云之外还需要深度图,请参考 ConvertPointCloud2DepthMap C++ 示例,该示例说明如何从点云计算灰度和 RGB 深度图。

将坐标系的原点移动到相机外壳的前部#

相机的坐标系原点位于相机外壳内部的光学中心。如果您更倾向于使用位于相机外壳前部(即沿 z 轴平移)的坐标系,则必须从 z 坐标中减去一个恒定的、设备特定的偏移量。通过获取以下参数的值,可以从相机中检索所需的偏移量: ZOffsetOriginToCameraFront 参数:

const double offset = camera.ZOffsetOriginToCameraFront.GetValue();

如果 (x,y,z) 是相机坐标系中某个点的坐标,则沿 z 轴移到相机坐标系外壳前部的坐标系中对应坐标 (x',y',z') 可以使用以下公式确定:

x' = x

y' = y

z' = z - offset

计算距离#

给定点的坐标 (x,y,z) (单位:毫米),该点到相机光学中心的距离可以使用以下公式计算:

d = sqrt( xx + yy + z*z )

距离 d' 相机外壳前部的距离计算如下:

z' = z - offset

d' = sqrt( xx + yy + z'*z')

将深度信息可视化为 RGB 图像#

您可以使用以下方案针对彩虹颜色映射,根据 z 坐标或距离值计算 RGB 值。这对于更好地可视化数据很有用。

首先,将 [minDepth..maxDepth] 值范围内的深度值转换为 10 位值。该 10 位深度值被映射到 4 个颜色范围,其中每个范围的分辨率为 8 位。

minDepth 和 maxDepth = 以下参数的值: DepthMin 和 DepthMax 参数,即相机当前的深度 ROI

深度值 映射到 Color 范围
0..255 红色至黄色
(255,0,0) -> (255,255,0)
256..511 黄色至绿色
(255,255,0) -> (0, 255, 0)
512..767 绿色至浅绿色
(0,255,0) -> (0,255,255)
768..1023 浅绿色至蓝色
(0,255,255) -> (0, 0, 255)

在以下代码片段中, depth 可以是 z 值或以毫米为单位的距离值。

const int minDepth = (int)m_camera.DepthMin.GetValue();
const int maxDepth = (int)m_camera.DepthMax.GetValue();

const double scale = 65536.0 / (maxDepth - minDepth);

for each pixel {
    // Set depth either to the corresponding z value or
    // a distance value calculated from the z value.
    // Clip depth if required.
    if (depth < minDepth)
        depth = minDepth;
    else if (depth > maxDepth)
        depth = maxDepth;
    // Compute RGB values.
    const uint16_t g = (uint16_t)((depth - minDepth) * scale);
    const uint16_t val = g >> 6 & 0xff;
    const uint16_t sel = g >> 14;
    uint32_t res = val << 8 | 0xff;
    if (sel & 0x01)
    {
        res = (~res) >> 8 & 0xffff;
    }
    if (sel & 0x02)
    {
        res = res << 8;
    }
    const uint8_t r = res & 0xff;
    res = res >> 8;
    const uint8_t g = res & 0xff;
    res = res >> 8;
    const uint8_t b = res & 0xff;
}