跳转到内容

Processing Measurement Results#

本主题告诉您如何处理 Basler blaze-101 相机的测量结果。

概述#

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

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

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

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

Processing Depth Maps#

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

结合 Scan3dCoordinateScaleScan3dPrincipalPointUScan3dPrincipalPointVScan3dFocalLength 参数提供的相机校准数据,可以从范围图中检索完整的 3D 信息。

有关如何配置相机以发送范围图以及如何访问范围图数据的信息,请参阅 GrabDepthMap C++ 示例。

从 2D 范围图计算 3D 坐标#

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

z [mm] = gray2mm * g

其中:

g = 范围图中的灰度值

gray2mm = Scan3dCoordinateScale 参数的值

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

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

其中:

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

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

(cx,cy) = Scan3dPrincipalPointUScan3dPrincipalPointV 参数的值,即主点

C++ 示例代码#

// Query the conversion factor required to convert gray values to distances:
// Choose the z axis first...
GenApi::CEnumerationPtr(camera.GetParameter("Scan3dCoordinateSelector"))->FromString("CoordinateC");
// ... then retrieve the conversion factor.
const double gray2mm = GenApi::CFloatPtr(camera.GetParameter("Scan3dCoordinateScale"))->GetValue();

// Retrieve calibration data from the camera.
const double cx = GenApi::CFloatPtr(camera.GetParameter("Scan3dPrincipalPointU"))->GetValue();
const double cy = GenApi::CFloatPtr(camera.GetParameter("Scan3dPrincipalPointV"))->GetValue();
const double f = GenApi::CFloatPtr(camera.GetParameter("Scan3dFocalLength"))->GetValue();

const int width = (int)parts[0].width;
const int height = (int)parts[0].height;
uint16_t* pDepthMap = (uint16_t*) parts[0].pData;
for ( int v = 0; v < height; ++v ) {
    for ( int u = 0; u < width; ++u>) {
        const uint16_t g = pDepthMap[v*width + u];
        const double z = gray2mm * g;
    }
}

Processing Point Clouds#

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

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

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

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

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

const double offset = GenApi::CFloatPtr(camera.GetParameter("ZOffsetOriginToCameraFront"))->GetValue();

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

x' = x
y' = y
z' = z - offset

Calculating Distances#

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

d = sqrt( x*x + y*y + z*z )

到相机外壳前部的距离 d’ 可以计算如下:

z' = z - offset
d' = sqrt( x*x + y*y + z'*z')

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

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

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

minDepthmaxDepth = DepthMinDepthMax 参数的值,即相机的当前深度 ROI

Depth Value 映射到 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 值或以 mm 为单位的距离值。

minDepth = (int) GenApi::CIntegerPtr(camera.GetParameter("DepthMin"))->GetValue();
maxDepth = (int) GenApi::CIntegerPtr(camera.GetParameter("DepthMax"))->GetValue();

const double scale = 65535.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;
}