跳至內容
測試伺服器
開發伺服器

處理量測結果#

本主題說明如何處理 Basler blaze 和 Smart blaze 相機的量測結果。

資訊

本主題中的所有資訊均適用於所有 blaze 和 Smart blaze 相機型號。為求簡潔,文中以「blaze」統稱所有型號。

概覽#

Basler blaze 相機可量測每個感光元件像素的光線行進距離。

利用這些距離,相機會針對每個感光元件像素,在右手座標系中計算 x、y、z 座標。座標系原點位於相機的光學中心(位於相機外殼內部)。y 軸朝下,z 軸背離相機朝外。

根據所選的 pixel format,相機會以深度圖或點雲的形式提供 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 Property

若要計算 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 Legacy SDK、pylon SDK 或 blaze ROS 驅動程式取得的深度圖,您必須使用下列公式:

測量距離 [mm] = Pixel_Value x Scan3dCoordinateScale[C]

對於使用 blaze Viewer 儲存的深度圖,請使用下列公式:

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

處理點雲#

無需進行額外處理即可從點雲中萃取 3D 資訊,因為點雲由相機座標系內的 x、y、z 座標三元組組成。

請參閱 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

深度值 對應至色彩範圍
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 為單位的距離值。

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;
}